@agent-native/core 0.69.0 → 0.70.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/README.md +15 -15
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +109 -0
- package/corpus/core/docs/design/durable-agent-runs.md +217 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/action.ts +89 -0
- package/corpus/core/src/agent/model-config.ts +0 -2
- package/corpus/core/src/agent/run-loop-with-resume.ts +48 -0
- package/corpus/core/src/changelog/parse.ts +245 -0
- package/corpus/core/src/cli/changelog.ts +199 -0
- package/corpus/core/src/cli/index.ts +19 -0
- package/corpus/core/src/cli/recap.ts +24 -1
- package/corpus/core/src/cli/skills.ts +74 -47
- package/corpus/core/src/client/AgentPanel.tsx +5 -3
- package/corpus/core/src/client/AssistantChat.tsx +8 -0
- package/corpus/core/src/client/CommandMenu.tsx +183 -75
- package/corpus/core/src/client/agent-chat-adapter.ts +44 -7
- package/corpus/core/src/client/analytics.ts +181 -0
- package/corpus/core/src/client/changelog/Changelog.tsx +321 -0
- package/corpus/core/src/client/client-surface.ts +41 -0
- package/corpus/core/src/client/composer/TiptapComposer.tsx +123 -12
- package/corpus/core/src/client/feedback-context.ts +4 -0
- package/corpus/core/src/client/index.ts +12 -0
- package/corpus/core/src/client/mcp-apps/McpAppRenderer.tsx +54 -0
- package/corpus/core/src/client/settings/useBuilderStatus.ts +82 -20
- package/corpus/core/src/client/sse-event-processor.ts +7 -1
- package/corpus/core/src/mcp/build-server.ts +57 -1
- package/corpus/core/src/mcp/embed-app.ts +197 -7
- package/corpus/core/src/mcp/oauth-route.ts +109 -13
- package/corpus/core/src/server/attribution.ts +211 -0
- package/corpus/core/src/server/auth.ts +6 -0
- package/corpus/core/src/server/better-auth-instance.ts +49 -5
- package/corpus/core/src/server/builder-browser.ts +27 -1
- package/corpus/core/src/server/core-routes-plugin.ts +136 -0
- package/corpus/core/src/server/google-oauth.ts +19 -6
- package/corpus/core/src/server/onboarding-html.ts +35 -0
- package/corpus/core/src/shared/mcp-embed-headers.ts +1 -1
- package/corpus/core/src/styles/agent-conversation.css +21 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +111 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +72 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +46 -14
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +22 -0
- package/corpus/templates/analytics/AGENTS.md +8 -1
- package/corpus/templates/analytics/CHANGELOG.md +10 -0
- package/corpus/templates/analytics/actions/install-dashboard-template.ts +99 -4
- package/corpus/templates/analytics/actions/open-traffic-dashboard.ts +1 -1
- package/corpus/templates/analytics/actions/update-dashboard.ts +39 -8
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +30 -3
- package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +180 -144
- package/corpus/templates/analytics/app/components/layout/Header.tsx +2 -3
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +7 -5
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +221 -215
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +6 -6
- package/corpus/templates/analytics/app/lib/demo-dashboard-path.ts +1 -1
- package/corpus/templates/analytics/app/lib/last-opened.ts +2 -1
- package/corpus/templates/analytics/app/pages/Settings.tsx +4 -0
- package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +3 -3
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/DashboardFilterBar.tsx +2 -2
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +32 -2
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +101 -99
- package/corpus/templates/analytics/app/pages/overview/OverviewPage.tsx +1 -1
- package/corpus/templates/analytics/app/routes/adhoc.$id.tsx +18 -5
- package/corpus/templates/analytics/app/routes/catalog.tsx +1 -1
- package/corpus/templates/analytics/app/routes/dashboards.$id.tsx +9 -0
- package/corpus/templates/analytics/app/routes/traffic.tsx +1 -1
- package/corpus/templates/analytics/changelog/2026-06-23-long-dashboard-and-analysis-names-in-the-sidebar-now-truncat.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-23-open-any-dashboard-chart-full-screen-in-a-modal-from-the-pan.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-23-the-dashboards-and-analyses-sidebar-settings-buttons-now-sta.md +6 -0
- package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +145 -0
- package/corpus/templates/analytics/server/db/index.ts +1 -1
- package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +9 -2
- package/corpus/templates/analytics/server/lib/demo-dashboards.ts +1 -1
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +2 -2
- package/corpus/templates/analytics/server/plugins/core-routes.ts +6 -6
- package/corpus/templates/assets/CHANGELOG.md +10 -0
- package/corpus/templates/assets/actions/generate-image.ts +24 -0
- package/corpus/templates/assets/app/components/layout/Sidebar.tsx +2 -2
- package/corpus/templates/assets/app/global.css +17 -1
- package/corpus/templates/assets/app/root.tsx +7 -1
- package/corpus/templates/assets/app/routes/_index.tsx +94 -14
- package/corpus/templates/assets/app/routes/settings.tsx +6 -0
- package/corpus/templates/assets/changelog/2026-06-23-chat-dates-in-the-sidebar-no-longer-wrap-onto-two-lines.md +6 -0
- package/corpus/templates/assets/changelog/2026-06-23-clicking-image-video-or-refine-on-the-start-screen-now-drops.md +6 -0
- package/corpus/templates/assets/changelog/2026-06-23-pick-your-image-generation-model-right-from-the-chat-model-m.md +6 -0
- package/corpus/templates/brain/CHANGELOG.md +10 -0
- package/corpus/templates/brain/app/root.tsx +7 -1
- package/corpus/templates/brain/app/routes/settings.tsx +8 -1
- package/corpus/templates/calendar/CHANGELOG.md +10 -0
- package/corpus/templates/calendar/app/pages/Settings.tsx +4 -0
- package/corpus/templates/calendar/app/root.tsx +7 -1
- package/corpus/templates/chat/CHANGELOG.md +10 -0
- package/corpus/templates/chat/app/root.tsx +7 -1
- package/corpus/templates/clips/CHANGELOG.md +10 -0
- package/corpus/templates/clips/app/components/library/library-grid.tsx +1 -20
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +33 -7
- package/corpus/templates/clips/app/components/player/sign-in-prompt-dialog.tsx +8 -0
- package/corpus/templates/clips/app/components/player/video-player.tsx +150 -20
- package/corpus/templates/clips/app/components/recorder/countdown-overlay.tsx +72 -48
- package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +7 -11
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +31 -0
- package/corpus/templates/clips/app/components/sharing/slack-share-hint.tsx +71 -0
- package/corpus/templates/clips/app/lib/countdown-audio-cue.ts +35 -17
- package/corpus/templates/clips/app/root.tsx +7 -1
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +15 -1
- package/corpus/templates/clips/app/routes/record.tsx +78 -5
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +86 -5
- package/corpus/templates/clips/changelog/2026-06-23-clips-shared-in-slack-no-longer-show-a-could-not-start-playb.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-made-the-play-button-on-shared-and-embedded-clips-scale-with.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-public-clip-share-links-now-show-whether-they-ll-play-inline.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-removed-select-button-from-library-hover-a-clip-to-select-it.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-screen-camera-recordings-now-keep-the-presenter-s-face-in-th.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-shared-video-links-now-play-for-anyone-without-signing-in.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-skip-or-cancel-the-recording-countdown-with-buttons-beside-t.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-the-desktop-camera-bubble-now-looks-sharp-the-instant-it-ope.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-the-desktop-recording-widget-now-grows-downward-only-when-yo.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-the-recording-start-sound-is-now-a-softer-more-modern-chime.md +6 -0
- package/corpus/templates/clips/chrome-extension/public/manifest.json +17 -8
- package/corpus/templates/clips/chrome-extension/src/background.ts +769 -180
- package/corpus/templates/clips/chrome-extension/src/content-script.ts +177 -0
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +466 -329
- package/corpus/templates/clips/chrome-extension/src/overlay.css +377 -0
- package/corpus/templates/clips/chrome-extension/src/overlay.html +12 -0
- package/corpus/templates/clips/chrome-extension/src/overlay.ts +330 -0
- package/corpus/templates/clips/chrome-extension/src/permission.html +227 -0
- package/corpus/templates/clips/chrome-extension/src/permission.ts +105 -0
- package/corpus/templates/clips/chrome-extension/src/popup.html +3 -0
- package/corpus/templates/clips/chrome-extension/src/popup.ts +50 -2
- package/corpus/templates/clips/chrome-extension/src/styles.css +50 -0
- package/corpus/templates/clips/chrome-extension/vite.config.ts +3 -0
- package/corpus/templates/clips/desktop/src/lib/audio-cue.ts +41 -24
- package/corpus/templates/clips/desktop/src/lib/bubble-webrtc.ts +119 -2
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +20 -0
- package/corpus/templates/clips/desktop/src/main.tsx +3 -0
- package/corpus/templates/clips/desktop/src/overlays/countdown.tsx +21 -2
- package/corpus/templates/clips/desktop/src/overlays/region-record-border.tsx +76 -0
- package/corpus/templates/clips/desktop/src/styles.css +119 -2
- package/corpus/templates/clips/desktop/src-tauri/capabilities/default.json +2 -1
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +140 -1
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +2 -0
- package/corpus/templates/clips/desktop/src-tauri/src/util.rs +4 -1
- package/corpus/templates/clips/server/routes/api/video/[recordingId].get.ts +85 -6
- package/corpus/templates/clips/shared/share-attribution.ts +79 -0
- package/corpus/templates/content/AGENTS.md +20 -3
- package/corpus/templates/content/CHANGELOG.md +10 -0
- package/corpus/templates/content/actions/_database-utils.ts +15 -0
- package/corpus/templates/content/actions/_property-utils.ts +371 -4
- package/corpus/templates/content/actions/configure-document-property.ts +35 -1
- package/corpus/templates/content/actions/create-content-database.ts +5 -1
- package/corpus/templates/content/actions/delete-document-property.ts +52 -2
- package/corpus/templates/content/actions/duplicate-document-property.ts +34 -17
- package/corpus/templates/content/actions/reorder-document-property.ts +79 -0
- package/corpus/templates/content/actions/set-document-property.ts +39 -0
- package/corpus/templates/content/app/components/editor/DocumentBlockFields.tsx +806 -0
- package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +226 -68
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +59 -30
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +25 -1
- package/corpus/templates/content/app/components/editor/blockFieldSaveController.ts +180 -0
- package/corpus/templates/content/app/components/editor/blockFieldSaveRegistry.ts +179 -0
- package/corpus/templates/content/app/components/editor/previewDocumentSaveController.ts +244 -0
- package/corpus/templates/content/app/components/editor/previewDocumentSaveRegistry.ts +132 -0
- package/corpus/templates/content/app/global.css +9 -0
- package/corpus/templates/content/app/hooks/use-document-properties.ts +21 -0
- package/corpus/templates/content/app/root.tsx +7 -1
- package/corpus/templates/content/server/db/schema.ts +30 -0
- package/corpus/templates/content/server/plugins/db.ts +87 -0
- package/corpus/templates/content/shared/api.ts +7 -0
- package/corpus/templates/content/shared/properties.ts +109 -0
- package/corpus/templates/design/CHANGELOG.md +10 -0
- package/corpus/templates/design/actions/generate-design.ts +4 -0
- package/corpus/templates/design/app/root.tsx +7 -1
- package/corpus/templates/design/app/routes/settings.tsx +10 -2
- package/corpus/templates/dispatch/CHANGELOG.md +10 -0
- package/corpus/templates/dispatch/app/root.tsx +7 -1
- package/corpus/templates/forms/.agents/skills/form-responses/SKILL.md +10 -0
- package/corpus/templates/forms/CHANGELOG.md +10 -0
- package/corpus/templates/forms/actions/export-responses.ts +6 -0
- package/corpus/templates/forms/actions/list-responses.ts +2 -0
- package/corpus/templates/forms/actions/response-insights.ts +2 -0
- package/corpus/templates/forms/app/pages/ResponsesPage.tsx +138 -1
- package/corpus/templates/forms/app/root.tsx +7 -1
- package/corpus/templates/forms/changelog/2026-06-23-response-tables-now-show-the-page-each-submission-came-from-.md +6 -0
- package/corpus/templates/forms/changelog/2026-06-23-response-tables-now-show-whether-feedback-came-from-the-web-.md +6 -0
- package/corpus/templates/forms/server/db/schema.ts +7 -0
- package/corpus/templates/forms/server/handlers/submissions.ts +19 -2
- package/corpus/templates/forms/server/lib/integrations.ts +76 -2
- package/corpus/templates/forms/server/plugins/db.ts +20 -0
- package/corpus/templates/forms/shared/types.ts +12 -0
- package/corpus/templates/macros/CHANGELOG.md +10 -0
- package/corpus/templates/macros/app/root.tsx +7 -1
- package/corpus/templates/mail/CHANGELOG.md +10 -0
- package/corpus/templates/mail/app/components/layout/CommandPalette.tsx +3 -0
- package/corpus/templates/mail/app/pages/SettingsPage.tsx +27 -0
- package/corpus/templates/plan/.agents/skills/visual-plan/SKILL.md +31 -17
- package/corpus/templates/plan/.agents/skills/visual-plan/references/wireframe.md +7 -4
- package/corpus/templates/plan/.agents/skills/visual-recap/SKILL.md +34 -24
- package/corpus/templates/plan/.agents/skills/visual-recap/references/wireframe.md +7 -4
- package/corpus/templates/plan/AGENTS.md +4 -0
- package/corpus/templates/plan/CHANGELOG.md +10 -0
- package/corpus/templates/plan/actions/view-screen.ts +5 -0
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +98 -1
- package/corpus/templates/plan/app/components/plan/wireframe/html-artboard.css +3 -1
- package/corpus/templates/plan/app/pages/PlansPage.tsx +107 -7
- package/corpus/templates/plan/app/root.tsx +7 -1
- package/corpus/templates/plan/changelog/2026-06-23-large-diagrams-in-a-plan-now-scroll-within-their-block-inste.md +6 -0
- package/corpus/templates/plan/shared/share-attribution.ts +72 -0
- package/corpus/templates/slides/CHANGELOG.md +10 -0
- package/corpus/templates/slides/app/root.tsx +7 -1
- package/corpus/templates/videos/CHANGELOG.md +4 -151
- package/corpus/templates/videos/app/root.tsx +7 -1
- package/dist/action.js +87 -0
- package/dist/action.js.map +1 -1
- package/dist/agent/engine/builder-engine.d.ts +1 -1
- package/dist/agent/engine/builder-engine.d.ts.map +1 -1
- package/dist/agent/model-config.d.ts +2 -2
- package/dist/agent/model-config.d.ts.map +1 -1
- package/dist/agent/model-config.js +0 -2
- package/dist/agent/model-config.js.map +1 -1
- package/dist/agent/run-loop-with-resume.d.ts +13 -0
- package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
- package/dist/agent/run-loop-with-resume.js +44 -0
- package/dist/agent/run-loop-with-resume.js.map +1 -1
- package/dist/changelog/parse.d.ts +70 -0
- package/dist/changelog/parse.d.ts.map +1 -0
- package/dist/changelog/parse.js +200 -0
- package/dist/changelog/parse.js.map +1 -0
- package/dist/cli/changelog.d.ts +4 -0
- package/dist/cli/changelog.d.ts.map +1 -0
- package/dist/cli/changelog.js +166 -0
- package/dist/cli/changelog.js.map +1 -0
- package/dist/cli/index.js +18 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/recap.d.ts.map +1 -1
- package/dist/cli/recap.js +22 -1
- package/dist/cli/recap.js.map +1 -1
- package/dist/cli/skills.d.ts +3 -3
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +74 -47
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +5 -3
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +6 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +2 -2
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/CommandMenu.d.ts +17 -1
- package/dist/client/CommandMenu.d.ts.map +1 -1
- package/dist/client/CommandMenu.js +49 -13
- package/dist/client/CommandMenu.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +43 -6
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/analytics.d.ts +18 -0
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +177 -0
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/changelog/Changelog.d.ts +47 -0
- package/dist/client/changelog/Changelog.d.ts.map +1 -0
- package/dist/client/changelog/Changelog.js +138 -0
- package/dist/client/changelog/Changelog.js.map +1 -0
- package/dist/client/client-surface.d.ts +17 -0
- package/dist/client/client-surface.d.ts.map +1 -0
- package/dist/client/client-surface.js +24 -0
- package/dist/client/client-surface.js.map +1 -0
- package/dist/client/composer/TiptapComposer.d.ts +26 -1
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +27 -5
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/feedback-context.d.ts +3 -0
- package/dist/client/feedback-context.d.ts.map +1 -1
- package/dist/client/feedback-context.js +2 -0
- package/dist/client/feedback-context.js.map +1 -1
- package/dist/client/index.d.ts +3 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +3 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/mcp-apps/McpAppRenderer.d.ts +1 -0
- package/dist/client/mcp-apps/McpAppRenderer.d.ts.map +1 -1
- package/dist/client/mcp-apps/McpAppRenderer.js +42 -1
- package/dist/client/mcp-apps/McpAppRenderer.js.map +1 -1
- package/dist/client/settings/useBuilderStatus.d.ts +2 -0
- package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
- package/dist/client/settings/useBuilderStatus.js +58 -10
- package/dist/client/settings/useBuilderStatus.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +7 -1
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/mcp/build-server.d.ts +21 -0
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +43 -1
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/mcp/embed-app.d.ts.map +1 -1
- package/dist/mcp/embed-app.js +197 -7
- package/dist/mcp/embed-app.js.map +1 -1
- package/dist/mcp/oauth-route.d.ts.map +1 -1
- package/dist/mcp/oauth-route.js +95 -12
- package/dist/mcp/oauth-route.js.map +1 -1
- package/dist/server/attribution.d.ts +83 -0
- package/dist/server/attribution.d.ts.map +1 -0
- package/dist/server/attribution.js +178 -0
- package/dist/server/attribution.js.map +1 -0
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +7 -0
- package/dist/server/auth.js.map +1 -1
- package/dist/server/better-auth-instance.d.ts +9 -1
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js +32 -2
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/builder-browser.d.ts +4 -0
- package/dist/server/builder-browser.d.ts.map +1 -1
- package/dist/server/builder-browser.js +20 -1
- package/dist/server/builder-browser.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts +25 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +101 -0
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/google-oauth.d.ts.map +1 -1
- package/dist/server/google-oauth.js +16 -2
- package/dist/server/google-oauth.js.map +1 -1
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +35 -0
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/shared/mcp-embed-headers.js +1 -1
- package/dist/shared/mcp-embed-headers.js.map +1 -1
- package/dist/styles/agent-conversation.css +21 -0
- package/dist/templates/workspace-core/.agents/skills/changelog/SKILL.md +111 -0
- package/dist/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +72 -0
- package/dist/templates/workspace-core/.agents/skills/tracking/SKILL.md +46 -14
- package/docs/design/durable-agent-runs.md +217 -0
- package/package.json +1 -1
- package/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +111 -0
- package/src/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +72 -0
- package/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +46 -14
- package/corpus/templates/analytics/app/pages/About.tsx +0 -108
- package/corpus/templates/analytics/app/routes/about.tsx +0 -9
- /package/corpus/templates/analytics/app/routes/{dashboards.tsx → dashboards._index.tsx} +0 -0
|
@@ -417,6 +417,11 @@ export interface TiptapComposerProps {
|
|
|
417
417
|
* Used by the Electron desktop app to route through the native IPC handler.
|
|
418
418
|
*/
|
|
419
419
|
onConnectProvider?: () => void;
|
|
420
|
+
/**
|
|
421
|
+
* Optional secondary model menu (e.g. an image-generation model) rendered as
|
|
422
|
+
* an extra section inside the model picker. Opt-in; omit for chat-only apps.
|
|
423
|
+
*/
|
|
424
|
+
imageModelMenu?: ComposerImageModelMenu;
|
|
420
425
|
/** Stable scope for persisted drafts, usually the active thread or tab id. */
|
|
421
426
|
draftScope?: string;
|
|
422
427
|
/** Keyed context nuggets staged for the next submitted prompt. */
|
|
@@ -669,6 +674,24 @@ function latestModelsOnly(models: string[]): string[] {
|
|
|
669
674
|
});
|
|
670
675
|
}
|
|
671
676
|
|
|
677
|
+
/**
|
|
678
|
+
* Optional secondary model menu for apps that drive a separate generation model
|
|
679
|
+
* alongside the chat LLM (e.g. the Assets app's image-generation model). When
|
|
680
|
+
* provided, the model picker renders an extra collapsible section so the user
|
|
681
|
+
* can see and pick both "what reasons about my request" (the chat model) and
|
|
682
|
+
* "what produces the output" (this model). Opt-in — omit it and nothing changes.
|
|
683
|
+
*/
|
|
684
|
+
export interface ComposerImageModelMenu {
|
|
685
|
+
/** Currently-selected model id for this secondary menu. */
|
|
686
|
+
value: string;
|
|
687
|
+
/** Selectable options (stable id + human label). */
|
|
688
|
+
options: Array<{ value: string; label: string }>;
|
|
689
|
+
/** Invoked when the user picks a different option. */
|
|
690
|
+
onChange: (value: string) => void;
|
|
691
|
+
/** Section header. Defaults to "Image model". */
|
|
692
|
+
label?: string;
|
|
693
|
+
}
|
|
694
|
+
|
|
672
695
|
function ModelSelector({
|
|
673
696
|
model,
|
|
674
697
|
effort = "auto",
|
|
@@ -677,6 +700,7 @@ function ModelSelector({
|
|
|
677
700
|
onEffortChange,
|
|
678
701
|
providerConnectStatusEnabled = true,
|
|
679
702
|
onConnectProvider,
|
|
703
|
+
imageModel,
|
|
680
704
|
}: {
|
|
681
705
|
model: string;
|
|
682
706
|
effort?: ReasoningEffort;
|
|
@@ -690,6 +714,7 @@ function ModelSelector({
|
|
|
690
714
|
onEffortChange?: (effort: ReasoningEffort) => void;
|
|
691
715
|
providerConnectStatusEnabled?: boolean;
|
|
692
716
|
onConnectProvider?: () => void;
|
|
717
|
+
imageModel?: ComposerImageModelMenu;
|
|
693
718
|
}) {
|
|
694
719
|
const [open, setOpen] = useState(false);
|
|
695
720
|
const autoModelGroup = engines.find((group) => group.models.includes("auto"));
|
|
@@ -744,6 +769,24 @@ function ModelSelector({
|
|
|
744
769
|
});
|
|
745
770
|
}, []);
|
|
746
771
|
|
|
772
|
+
// The reasoning effort list is collapsed by default — it's a secondary
|
|
773
|
+
// control most users don't touch, so it stays tucked behind a header that
|
|
774
|
+
// reveals the current effort at a glance. Reset to collapsed on each open.
|
|
775
|
+
const [reasoningExpanded, setReasoningExpanded] = useState(false);
|
|
776
|
+
useEffect(() => {
|
|
777
|
+
if (open) setReasoningExpanded(false);
|
|
778
|
+
}, [open]);
|
|
779
|
+
|
|
780
|
+
// The optional image-model section follows the same collapsed-by-default
|
|
781
|
+
// pattern; the current selection shows next to the header.
|
|
782
|
+
const [imageExpanded, setImageExpanded] = useState(false);
|
|
783
|
+
useEffect(() => {
|
|
784
|
+
if (open) setImageExpanded(false);
|
|
785
|
+
}, [open]);
|
|
786
|
+
const imageModelLabel =
|
|
787
|
+
imageModel?.options.find((option) => option.value === imageModel.value)
|
|
788
|
+
?.label ?? imageModel?.value;
|
|
789
|
+
|
|
747
790
|
// When Builder.io isn't connected, surface a one-click connect path —
|
|
748
791
|
// it unlocks every model family (Claude, OpenAI, Gemini) without the
|
|
749
792
|
// user having to paste individual API keys.
|
|
@@ -835,6 +878,52 @@ function ModelSelector({
|
|
|
835
878
|
<div className="my-1 border-t border-border" />
|
|
836
879
|
</>
|
|
837
880
|
)}
|
|
881
|
+
{imageModel && imageModel.options.length > 0 && (
|
|
882
|
+
<>
|
|
883
|
+
<div className="flex items-center hover:bg-accent/30">
|
|
884
|
+
<button
|
|
885
|
+
type="button"
|
|
886
|
+
aria-expanded={imageExpanded}
|
|
887
|
+
onClick={() => setImageExpanded((prev) => !prev)}
|
|
888
|
+
className="flex flex-1 min-w-0 items-center gap-1.5 px-2 py-1.5 cursor-pointer text-left"
|
|
889
|
+
>
|
|
890
|
+
{imageExpanded ? (
|
|
891
|
+
<IconChevronDown className="h-3 w-3 shrink-0 text-muted-foreground" />
|
|
892
|
+
) : (
|
|
893
|
+
<IconChevronRight className="h-3 w-3 shrink-0 text-muted-foreground" />
|
|
894
|
+
)}
|
|
895
|
+
<span className="text-[11px] font-medium text-muted-foreground uppercase tracking-wide shrink-0">
|
|
896
|
+
{imageModel.label ?? "Image model"}
|
|
897
|
+
</span>
|
|
898
|
+
{!imageExpanded && imageModelLabel && (
|
|
899
|
+
<span className="text-[11px] text-muted-foreground/80 truncate">
|
|
900
|
+
{imageModelLabel}
|
|
901
|
+
</span>
|
|
902
|
+
)}
|
|
903
|
+
</button>
|
|
904
|
+
</div>
|
|
905
|
+
{imageExpanded &&
|
|
906
|
+
imageModel.options.map((option) => (
|
|
907
|
+
<button
|
|
908
|
+
key={option.value}
|
|
909
|
+
type="button"
|
|
910
|
+
onClick={() => {
|
|
911
|
+
imageModel.onChange(option.value);
|
|
912
|
+
setImageExpanded(false);
|
|
913
|
+
}}
|
|
914
|
+
className="flex w-full items-center gap-3 pl-7 pr-3 py-1.5 text-left hover:bg-accent/50"
|
|
915
|
+
>
|
|
916
|
+
<span className="flex-1 min-w-0 text-[13px] text-foreground truncate">
|
|
917
|
+
{option.label}
|
|
918
|
+
</span>
|
|
919
|
+
{option.value === imageModel.value && (
|
|
920
|
+
<IconCheck className="h-3.5 w-3.5 shrink-0 text-blue-500" />
|
|
921
|
+
)}
|
|
922
|
+
</button>
|
|
923
|
+
))}
|
|
924
|
+
<div className="my-1 border-t border-border" />
|
|
925
|
+
</>
|
|
926
|
+
)}
|
|
838
927
|
{autoModelGroup && (
|
|
839
928
|
<button
|
|
840
929
|
type="button"
|
|
@@ -930,24 +1019,44 @@ function ModelSelector({
|
|
|
930
1019
|
{effortOptions.length > 0 && (
|
|
931
1020
|
<>
|
|
932
1021
|
<div className="my-1 border-t border-border" />
|
|
933
|
-
<div className="
|
|
934
|
-
Reasoning
|
|
935
|
-
</div>
|
|
936
|
-
{effortOptions.map((option) => (
|
|
1022
|
+
<div className="flex items-center hover:bg-accent/30">
|
|
937
1023
|
<button
|
|
938
|
-
key={option}
|
|
939
1024
|
type="button"
|
|
940
|
-
|
|
941
|
-
|
|
1025
|
+
aria-expanded={reasoningExpanded}
|
|
1026
|
+
onClick={() => setReasoningExpanded((prev) => !prev)}
|
|
1027
|
+
className="flex flex-1 min-w-0 items-center gap-1.5 px-2 py-1.5 cursor-pointer text-left"
|
|
942
1028
|
>
|
|
943
|
-
|
|
944
|
-
|
|
1029
|
+
{reasoningExpanded ? (
|
|
1030
|
+
<IconChevronDown className="h-3 w-3 shrink-0 text-muted-foreground" />
|
|
1031
|
+
) : (
|
|
1032
|
+
<IconChevronRight className="h-3 w-3 shrink-0 text-muted-foreground" />
|
|
1033
|
+
)}
|
|
1034
|
+
<span className="text-[11px] font-medium text-muted-foreground uppercase tracking-wide shrink-0">
|
|
1035
|
+
Reasoning
|
|
945
1036
|
</span>
|
|
946
|
-
{
|
|
947
|
-
<
|
|
1037
|
+
{!reasoningExpanded && (
|
|
1038
|
+
<span className="text-[11px] text-muted-foreground/80 truncate">
|
|
1039
|
+
{reasoningEffortLabel(effort)}
|
|
1040
|
+
</span>
|
|
948
1041
|
)}
|
|
949
1042
|
</button>
|
|
950
|
-
|
|
1043
|
+
</div>
|
|
1044
|
+
{reasoningExpanded &&
|
|
1045
|
+
effortOptions.map((option) => (
|
|
1046
|
+
<button
|
|
1047
|
+
key={option}
|
|
1048
|
+
type="button"
|
|
1049
|
+
onClick={() => onEffortChange?.(option)}
|
|
1050
|
+
className="flex w-full items-center gap-3 pl-7 pr-3 py-1.5 text-left hover:bg-accent/50"
|
|
1051
|
+
>
|
|
1052
|
+
<span className="flex-1 min-w-0 text-[13px] text-foreground truncate">
|
|
1053
|
+
{reasoningEffortLabel(option)}
|
|
1054
|
+
</span>
|
|
1055
|
+
{option === effort && (
|
|
1056
|
+
<IconCheck className="h-3.5 w-3.5 shrink-0 text-blue-500" />
|
|
1057
|
+
)}
|
|
1058
|
+
</button>
|
|
1059
|
+
))}
|
|
951
1060
|
</>
|
|
952
1061
|
)}
|
|
953
1062
|
</PopoverContent>
|
|
@@ -994,6 +1103,7 @@ export function TiptapComposer({
|
|
|
994
1103
|
onEffortChange,
|
|
995
1104
|
providerConnectStatusEnabled,
|
|
996
1105
|
onConnectProvider,
|
|
1106
|
+
imageModelMenu,
|
|
997
1107
|
draftScope,
|
|
998
1108
|
contextItems = [],
|
|
999
1109
|
onRemoveContextItem,
|
|
@@ -2091,6 +2201,7 @@ export function TiptapComposer({
|
|
|
2091
2201
|
onEffortChange={onEffortChange}
|
|
2092
2202
|
providerConnectStatusEnabled={providerConnectStatusEnabled}
|
|
2093
2203
|
onConnectProvider={onConnectProvider}
|
|
2204
|
+
imageModel={imageModelMenu}
|
|
2094
2205
|
/>
|
|
2095
2206
|
)}
|
|
2096
2207
|
{execMode && onExecModeChange && (
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { getActiveRun } from "./active-run-state.js";
|
|
2
|
+
import { getClientSurface, type ClientSurface } from "./client-surface.js";
|
|
2
3
|
import { scrubUrl } from "./url-scrub.js";
|
|
3
4
|
|
|
4
5
|
export interface FeedbackClientContext {
|
|
5
6
|
chatSessionIds: string[];
|
|
6
7
|
activeRunId?: string;
|
|
7
8
|
pageUrl?: string;
|
|
9
|
+
/** Runtime shell the feedback was sent from: web, electron, or tauri. */
|
|
10
|
+
clientSurface?: ClientSurface;
|
|
8
11
|
}
|
|
9
12
|
|
|
10
13
|
export interface FeedbackClientContextOptions {
|
|
@@ -81,6 +84,7 @@ export function getFeedbackClientContext(
|
|
|
81
84
|
if (activeRun?.runId) context.activeRunId = activeRun.runId;
|
|
82
85
|
if (typeof window !== "undefined") {
|
|
83
86
|
context.pageUrl = scrubUrl(window.location.href);
|
|
87
|
+
context.clientSurface = getClientSurface();
|
|
84
88
|
}
|
|
85
89
|
return context;
|
|
86
90
|
}
|
|
@@ -609,6 +609,7 @@ export {
|
|
|
609
609
|
type StarfieldBackgroundProps,
|
|
610
610
|
} from "./StarfieldBackground.js";
|
|
611
611
|
export { FeedbackButton, type FeedbackButtonProps } from "./FeedbackButton.js";
|
|
612
|
+
export { getClientSurface, type ClientSurface } from "./client-surface.js";
|
|
612
613
|
export {
|
|
613
614
|
DevDatabaseLink,
|
|
614
615
|
type DevDatabaseLinkProps,
|
|
@@ -643,10 +644,12 @@ export {
|
|
|
643
644
|
trackEvent,
|
|
644
645
|
trackSessionStatus,
|
|
645
646
|
configureTracking,
|
|
647
|
+
getFirstTouchAttribution,
|
|
646
648
|
setSentryUser,
|
|
647
649
|
captureError,
|
|
648
650
|
captureClientException,
|
|
649
651
|
type ClientCaptureContext,
|
|
652
|
+
type FirstTouchAttribution,
|
|
650
653
|
} from "./analytics.js";
|
|
651
654
|
export { track } from "./track.js";
|
|
652
655
|
export {
|
|
@@ -713,6 +716,15 @@ export {
|
|
|
713
716
|
type CommandItemProps,
|
|
714
717
|
type CommandShortcutProps,
|
|
715
718
|
} from "./CommandMenu.js";
|
|
719
|
+
export {
|
|
720
|
+
ChangelogDialog,
|
|
721
|
+
ChangelogSettingsCard,
|
|
722
|
+
useChangelogSeen,
|
|
723
|
+
parseChangelog,
|
|
724
|
+
type ChangelogDialogProps,
|
|
725
|
+
type ChangelogSettingsCardProps,
|
|
726
|
+
type ChangelogEntry,
|
|
727
|
+
} from "./changelog/Changelog.js";
|
|
716
728
|
export {
|
|
717
729
|
DevOverlay,
|
|
718
730
|
useDevOverlayShortcut,
|
|
@@ -13,6 +13,7 @@ import { agentNativePath } from "../api-path.js";
|
|
|
13
13
|
import { cn } from "../utils.js";
|
|
14
14
|
|
|
15
15
|
export const DEFAULT_MCP_APP_IFRAME_HEIGHT = 650;
|
|
16
|
+
export const MCP_APP_INITIALIZE_TIMEOUT_MS = 8000;
|
|
16
17
|
const MIN_IFRAME_HEIGHT = 220;
|
|
17
18
|
const VIEWPORT_MARGIN = 16;
|
|
18
19
|
const SANDBOX_FLAGS = "allow-scripts allow-forms allow-popups";
|
|
@@ -46,6 +47,7 @@ export function McpAppRenderer({ app, className }: McpAppRendererProps) {
|
|
|
46
47
|
() => (resourceHtml ? injectCsp(resourceHtml, csp) : ""),
|
|
47
48
|
[resourceHtml, csp],
|
|
48
49
|
);
|
|
50
|
+
const externalOpenUrl = useMemo(() => openUrlFromMcpApp(app), [app]);
|
|
49
51
|
|
|
50
52
|
useEffect(() => {
|
|
51
53
|
desiredHeightRef.current = DEFAULT_MCP_APP_IFRAME_HEIGHT;
|
|
@@ -115,6 +117,11 @@ export function McpAppRenderer({ app, className }: McpAppRendererProps) {
|
|
|
115
117
|
if (!iframe?.contentWindow || !srcDoc || loadedSrcDoc !== srcDoc) return;
|
|
116
118
|
|
|
117
119
|
let closed = false;
|
|
120
|
+
const initializeTimer = window.setTimeout(() => {
|
|
121
|
+
if (closed) return;
|
|
122
|
+
setReady(false);
|
|
123
|
+
setError("MCP App did not finish initializing.");
|
|
124
|
+
}, MCP_APP_INITIALIZE_TIMEOUT_MS);
|
|
118
125
|
const bridge = new AppBridge(
|
|
119
126
|
null,
|
|
120
127
|
{ name: "Agent Native", version: "1.0.0" },
|
|
@@ -144,7 +151,11 @@ export function McpAppRenderer({ app, className }: McpAppRendererProps) {
|
|
|
144
151
|
});
|
|
145
152
|
bridge.addEventListener("initialized", () => {
|
|
146
153
|
if (closed) return;
|
|
154
|
+
clearTimeout(initializeTimer);
|
|
147
155
|
setReady(true);
|
|
156
|
+
// Clear any error the initialize timeout may have set before a slow app
|
|
157
|
+
// finished — otherwise the error overlay stays stuck over a working app.
|
|
158
|
+
setError(null);
|
|
148
159
|
void bridge.sendToolInput({ arguments: app.toolInput });
|
|
149
160
|
void bridge.sendToolResult(app.toolResult as CallToolResult);
|
|
150
161
|
});
|
|
@@ -194,12 +205,14 @@ export function McpAppRenderer({ app, className }: McpAppRendererProps) {
|
|
|
194
205
|
setError(null);
|
|
195
206
|
bridge.connect(transport).catch((err: any) => {
|
|
196
207
|
if (!closed) {
|
|
208
|
+
clearTimeout(initializeTimer);
|
|
197
209
|
setError(err?.message ?? "Failed to initialize MCP App.");
|
|
198
210
|
}
|
|
199
211
|
});
|
|
200
212
|
|
|
201
213
|
return () => {
|
|
202
214
|
closed = true;
|
|
215
|
+
clearTimeout(initializeTimer);
|
|
203
216
|
setReady(false);
|
|
204
217
|
void bridge
|
|
205
218
|
.teardownResource({}, { timeout: 500 })
|
|
@@ -244,6 +257,17 @@ export function McpAppRenderer({ app, className }: McpAppRendererProps) {
|
|
|
244
257
|
<div className="agent-mcp-app__error">
|
|
245
258
|
<IconAlertTriangle size={15} />
|
|
246
259
|
<span>{error}</span>
|
|
260
|
+
{externalOpenUrl && (
|
|
261
|
+
<button
|
|
262
|
+
type="button"
|
|
263
|
+
className="agent-mcp-app__open"
|
|
264
|
+
onClick={() =>
|
|
265
|
+
window.open(externalOpenUrl, "_blank", "noopener,noreferrer")
|
|
266
|
+
}
|
|
267
|
+
>
|
|
268
|
+
Open in new tab
|
|
269
|
+
</button>
|
|
270
|
+
)}
|
|
247
271
|
</div>
|
|
248
272
|
)}
|
|
249
273
|
<iframe
|
|
@@ -281,6 +305,36 @@ function htmlFromResource(
|
|
|
281
305
|
}
|
|
282
306
|
}
|
|
283
307
|
|
|
308
|
+
function recordValue(value: unknown): Record<string, unknown> | null {
|
|
309
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
310
|
+
? (value as Record<string, unknown>)
|
|
311
|
+
: null;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function openUrlRecordValue(value: unknown): string | null {
|
|
315
|
+
const record = recordValue(value);
|
|
316
|
+
const webUrl = record?.webUrl;
|
|
317
|
+
return typeof webUrl === "string" && isSafeExternalUrl(webUrl)
|
|
318
|
+
? webUrl
|
|
319
|
+
: null;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function openUrlFromMcpApp(app: AgentMcpAppPayload): string | null {
|
|
323
|
+
const result = recordValue(app.toolResult);
|
|
324
|
+
const meta = recordValue(result?._meta);
|
|
325
|
+
const fromMeta = openUrlRecordValue(meta?.["agent-native/openLink"]);
|
|
326
|
+
if (fromMeta) return fromMeta;
|
|
327
|
+
|
|
328
|
+
const structuredContent = recordValue(result?.structuredContent);
|
|
329
|
+
const fromStructured = openUrlRecordValue(structuredContent?.openLink);
|
|
330
|
+
if (fromStructured) return fromStructured;
|
|
331
|
+
|
|
332
|
+
const directUrl = structuredContent?.url ?? result?.url;
|
|
333
|
+
return typeof directUrl === "string" && isSafeExternalUrl(directUrl)
|
|
334
|
+
? directUrl
|
|
335
|
+
: null;
|
|
336
|
+
}
|
|
337
|
+
|
|
284
338
|
export function supportedMcpAppPermissions(
|
|
285
339
|
permissions: McpUiResourcePermissions | undefined,
|
|
286
340
|
): McpUiResourcePermissions {
|
|
@@ -195,6 +195,8 @@ const BUILDER_STATE_PARAM = "_an_state";
|
|
|
195
195
|
const BUILDER_SIGNUP_SOURCE_PARAM = "signupSource";
|
|
196
196
|
const BUILDER_AGENT_NATIVE_FLOW_PARAM = "agentNativeFlow";
|
|
197
197
|
const BUILDER_AGENT_NATIVE_CONNECT_SOURCE_PARAM = "agentNativeConnectSource";
|
|
198
|
+
const BUILDER_AGENT_NATIVE_APP_PARAM = "agentNativeApp";
|
|
199
|
+
const BUILDER_AGENT_NATIVE_TEMPLATE_PARAM = "agentNativeTemplate";
|
|
198
200
|
const BUILDER_SIGNUP_SOURCE = "agent-native";
|
|
199
201
|
const STATUS_CONNECT_URL_TTL_MS = 9 * 60 * 1000;
|
|
200
202
|
|
|
@@ -224,42 +226,102 @@ function inferBuilderConnectTrackingFlow(source: string | undefined): string {
|
|
|
224
226
|
return "connect_llm";
|
|
225
227
|
}
|
|
226
228
|
|
|
229
|
+
function normalizeTrackingSlug(
|
|
230
|
+
value: string | null | undefined,
|
|
231
|
+
): string | null {
|
|
232
|
+
const trimmed = value?.trim();
|
|
233
|
+
if (!trimmed) return null;
|
|
234
|
+
const unscoped = trimmed.startsWith("@")
|
|
235
|
+
? (trimmed.split("/").pop() ?? trimmed)
|
|
236
|
+
: trimmed;
|
|
237
|
+
const slug = unscoped
|
|
238
|
+
.toLowerCase()
|
|
239
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
240
|
+
.replace(/^-+|-+$/g, "");
|
|
241
|
+
return slug || null;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function inferBuilderConnectTrackingIdentity(options: {
|
|
245
|
+
app?: string;
|
|
246
|
+
template?: string;
|
|
247
|
+
}): { app: string | null; template: string | null } {
|
|
248
|
+
const env = (import.meta.env as Record<string, string | undefined>) ?? {};
|
|
249
|
+
const app =
|
|
250
|
+
normalizeTrackingSlug(options.app) ??
|
|
251
|
+
normalizeTrackingSlug(env.VITE_AGENT_NATIVE_APP) ??
|
|
252
|
+
(typeof window !== "undefined"
|
|
253
|
+
? normalizeTrackingSlug(window.location.hostname.split(".")[0])
|
|
254
|
+
: null);
|
|
255
|
+
const template =
|
|
256
|
+
normalizeTrackingSlug(options.template) ??
|
|
257
|
+
normalizeTrackingSlug(env.VITE_AGENT_NATIVE_TEMPLATE) ??
|
|
258
|
+
normalizeTrackingSlug(env.VITE_APP_TEMPLATE) ??
|
|
259
|
+
(app?.startsWith("agent-native-")
|
|
260
|
+
? normalizeTrackingSlug(app.slice("agent-native-".length))
|
|
261
|
+
: app && app !== "localhost"
|
|
262
|
+
? app
|
|
263
|
+
: null);
|
|
264
|
+
|
|
265
|
+
return { app, template };
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function applyBuilderConnectTrackingParams(
|
|
269
|
+
params: URLSearchParams,
|
|
270
|
+
tracking: {
|
|
271
|
+
source?: string | null;
|
|
272
|
+
flow: string;
|
|
273
|
+
app?: string | null;
|
|
274
|
+
template?: string | null;
|
|
275
|
+
},
|
|
276
|
+
) {
|
|
277
|
+
params.set(BUILDER_SIGNUP_SOURCE_PARAM, BUILDER_SIGNUP_SOURCE);
|
|
278
|
+
params.set(BUILDER_AGENT_NATIVE_FLOW_PARAM, tracking.flow);
|
|
279
|
+
if (tracking.source) {
|
|
280
|
+
params.set(BUILDER_AGENT_NATIVE_CONNECT_SOURCE_PARAM, tracking.source);
|
|
281
|
+
}
|
|
282
|
+
if (tracking.app) {
|
|
283
|
+
params.set(BUILDER_AGENT_NATIVE_APP_PARAM, tracking.app);
|
|
284
|
+
}
|
|
285
|
+
if (tracking.template) {
|
|
286
|
+
params.set(BUILDER_AGENT_NATIVE_TEMPLATE_PARAM, tracking.template);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
227
290
|
export function withBuilderConnectTrackingParams(
|
|
228
291
|
url: string,
|
|
229
|
-
options: {
|
|
292
|
+
options: {
|
|
293
|
+
source?: string;
|
|
294
|
+
flow?: string;
|
|
295
|
+
app?: string;
|
|
296
|
+
template?: string;
|
|
297
|
+
} = {},
|
|
230
298
|
): string {
|
|
231
299
|
const source = cleanTrackingParam(options.source);
|
|
232
300
|
const flow =
|
|
233
301
|
cleanTrackingParam(options.flow) ??
|
|
234
302
|
inferBuilderConnectTrackingFlow(source ?? undefined);
|
|
303
|
+
const { app, template } = inferBuilderConnectTrackingIdentity(options);
|
|
235
304
|
const origin =
|
|
236
305
|
typeof window !== "undefined" ? window.location.origin : "http://localhost";
|
|
237
306
|
|
|
238
307
|
try {
|
|
239
308
|
const parsed = new URL(url, origin);
|
|
240
|
-
parsed.searchParams
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
);
|
|
247
|
-
}
|
|
309
|
+
applyBuilderConnectTrackingParams(parsed.searchParams, {
|
|
310
|
+
source,
|
|
311
|
+
flow,
|
|
312
|
+
app,
|
|
313
|
+
template,
|
|
314
|
+
});
|
|
248
315
|
|
|
249
316
|
const redirectUrl = parsed.searchParams.get("redirect_url");
|
|
250
317
|
if (redirectUrl) {
|
|
251
318
|
const parsedRedirect = new URL(redirectUrl);
|
|
252
|
-
parsedRedirect.searchParams
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
parsedRedirect.searchParams.set(
|
|
259
|
-
BUILDER_AGENT_NATIVE_CONNECT_SOURCE_PARAM,
|
|
260
|
-
source,
|
|
261
|
-
);
|
|
262
|
-
}
|
|
319
|
+
applyBuilderConnectTrackingParams(parsedRedirect.searchParams, {
|
|
320
|
+
source,
|
|
321
|
+
flow,
|
|
322
|
+
app,
|
|
323
|
+
template,
|
|
324
|
+
});
|
|
263
325
|
parsed.searchParams.set("redirect_url", parsedRedirect.toString());
|
|
264
326
|
}
|
|
265
327
|
|
|
@@ -233,7 +233,13 @@ function isAutoRecoverableError(ev: SSEEvent, errMsg: string): boolean {
|
|
|
233
233
|
// same wall. This used to send the chat into a 32-continuation runaway
|
|
234
234
|
// (each turn cleared+regenerated visible content) for users hitting a
|
|
235
235
|
// misbehaving Builder route. Surface the error instead.
|
|
236
|
-
code === "builder_gateway_error"
|
|
236
|
+
code === "builder_gateway_error" ||
|
|
237
|
+
// The hosted run exhausted its in-invocation continuation budget without
|
|
238
|
+
// finishing (run-loop-with-resume.ts). It's flagged `recoverable: true` so
|
|
239
|
+
// the recovery banner reads "stopped before finishing", but it must NOT
|
|
240
|
+
// auto-continue: another POST would hit the same ~40s wall and churn. The
|
|
241
|
+
// user retries deliberately (ideally as a single bulk action).
|
|
242
|
+
code === "run_budget_exhausted"
|
|
237
243
|
) {
|
|
238
244
|
return false;
|
|
239
245
|
}
|
|
@@ -184,6 +184,46 @@ export interface MCPRequestMeta {
|
|
|
184
184
|
* `config.actions`. Set by `mountMCP` from `verifyAuth`.
|
|
185
185
|
*/
|
|
186
186
|
fullSurface?: boolean;
|
|
187
|
+
/**
|
|
188
|
+
* Whether this request may receive inline MCP App embeds (the `ui://`
|
|
189
|
+
* resource reference hosts render in an iframe). Resolved once per request by
|
|
190
|
+
* `createMCPServerForRequest` from `isMcpAppsInlineEnabled(identity)` — the
|
|
191
|
+
* deploy-toggleable kill switch. When `false`, no MCP App resource is
|
|
192
|
+
* advertised or referenced and tool results fall back to their deep-link
|
|
193
|
+
* text. Defaults to disabled when unset.
|
|
194
|
+
*/
|
|
195
|
+
inlineMcpApps?: boolean;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Deploy-toggleable kill switch for inline MCP App embeds — the `ui://`
|
|
200
|
+
* resource reference hosts like Codex / Cursor / ChatGPT render in a sandboxed
|
|
201
|
+
* iframe. **Off by default**, so a not-yet-verified inline embed never reaches
|
|
202
|
+
* normal users; flip it on per environment with `AGENT_NATIVE_MCP_APPS_INLINE=1`
|
|
203
|
+
* and a redeploy. While the global switch is off, accounts listed in
|
|
204
|
+
* `AGENT_NATIVE_MCP_APPS_INLINE_ALLOW_EMAILS` (comma/space separated) still get
|
|
205
|
+
* inline embeds, so you can keep verifying a fix in production before enabling
|
|
206
|
+
* it for everyone. Requires no skills/instructions change — when disabled, tool
|
|
207
|
+
* results simply fall back to their deep-link text.
|
|
208
|
+
*/
|
|
209
|
+
export function isMcpAppsInlineEnabled(
|
|
210
|
+
identity: MCPCallerIdentity | undefined,
|
|
211
|
+
): boolean {
|
|
212
|
+
const flag = process.env.AGENT_NATIVE_MCP_APPS_INLINE?.trim().toLowerCase();
|
|
213
|
+
if (flag === "1" || flag === "true" || flag === "yes" || flag === "on") {
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
const email = identity?.userEmail?.trim().toLowerCase();
|
|
217
|
+
if (email) {
|
|
218
|
+
const allowed = (
|
|
219
|
+
process.env.AGENT_NATIVE_MCP_APPS_INLINE_ALLOW_EMAILS ?? ""
|
|
220
|
+
)
|
|
221
|
+
.split(/[\s,]+/)
|
|
222
|
+
.map((value) => value.trim().toLowerCase())
|
|
223
|
+
.filter(Boolean);
|
|
224
|
+
if (allowed.includes(email)) return true;
|
|
225
|
+
}
|
|
226
|
+
return false;
|
|
187
227
|
}
|
|
188
228
|
|
|
189
229
|
type McpOAuthScope = (typeof MCP_OAUTH_SCOPES)[number];
|
|
@@ -708,7 +748,7 @@ function safeUiSegment(value: string | undefined, fallback: string): string {
|
|
|
708
748
|
|
|
709
749
|
// ChatGPT and Claude cache MCP App resource HTML by `ui://` URI. Bump this
|
|
710
750
|
// when the shared shell changes in a way that must invalidate host caches.
|
|
711
|
-
const MCP_APP_RESOURCE_SHELL_VERSION = "shell-
|
|
751
|
+
const MCP_APP_RESOURCE_SHELL_VERSION = "shell-v46";
|
|
712
752
|
|
|
713
753
|
function legacyDefaultMcpAppUri(config: MCPConfig, actionName: string): string {
|
|
714
754
|
const app = safeUiSegment(config.appId ?? config.name, "agent-native");
|
|
@@ -912,6 +952,12 @@ async function resolveMcpAppResource(
|
|
|
912
952
|
): Promise<ResolvedMcpAppResource | null> {
|
|
913
953
|
const resource = entry.mcpApp?.resource;
|
|
914
954
|
if (!resource) return null;
|
|
955
|
+
// Inline MCP App embeds are gated behind the deploy-toggleable kill switch
|
|
956
|
+
// (default off). When disabled, advertise no resource and attach no embed
|
|
957
|
+
// reference so hosts fall back to the tool's deep-link text instead of an
|
|
958
|
+
// iframe. This is the single chokepoint for every embed surface: tools/list
|
|
959
|
+
// descriptor meta, tools/call result meta, resources/list, resources/read.
|
|
960
|
+
if (!requestMeta?.inlineMcpApps) return null;
|
|
915
961
|
const resolvedUri = getMcpAppResourceUri(config, actionName, entry);
|
|
916
962
|
if (!resolvedUri) return null;
|
|
917
963
|
const description = resource.description ?? entry.tool.description;
|
|
@@ -1192,6 +1238,16 @@ export async function createMCPServerForRequest(
|
|
|
1192
1238
|
? { userEmail: ownerFromEnv, orgDomain: undefined }
|
|
1193
1239
|
: undefined);
|
|
1194
1240
|
|
|
1241
|
+
// Resolve the inline-MCP-App kill switch once per request from the effective
|
|
1242
|
+
// identity + environment, then thread it through `requestMeta` so every
|
|
1243
|
+
// resource/tool handler below honors the same decision. An explicit value on
|
|
1244
|
+
// the incoming meta (tests / embedded callers) wins.
|
|
1245
|
+
requestMeta = {
|
|
1246
|
+
...(requestMeta ?? {}),
|
|
1247
|
+
inlineMcpApps:
|
|
1248
|
+
requestMeta?.inlineMcpApps ?? isMcpAppsInlineEnabled(effectiveIdentity),
|
|
1249
|
+
};
|
|
1250
|
+
|
|
1195
1251
|
// The action set the request handlers operate on = base actions + generic
|
|
1196
1252
|
// cross-app builtins (template wins on name collision). An authenticated
|
|
1197
1253
|
// real caller (connect-minted token / `mcp install` owner / production —
|