@agent-native/core 0.83.0 → 0.84.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +28 -0
- package/corpus/core/README.md +2 -2
- package/corpus/core/docs/content/cloneable-saas.mdx +2 -2
- package/corpus/core/docs/content/faq.mdx +1 -1
- package/corpus/core/docs/content/locales/ar-SA/cloneable-saas.mdx +2 -2
- package/corpus/core/docs/content/locales/ar-SA/faq.mdx +1 -1
- package/corpus/core/docs/content/locales/ar-SA/template-chat.mdx +1 -1
- package/corpus/core/docs/content/locales/de-DE/cloneable-saas.mdx +2 -2
- package/corpus/core/docs/content/locales/de-DE/faq.mdx +1 -1
- package/corpus/core/docs/content/locales/de-DE/template-chat.mdx +1 -1
- package/corpus/core/docs/content/locales/es-ES/cloneable-saas.mdx +2 -2
- package/corpus/core/docs/content/locales/es-ES/faq.mdx +1 -1
- package/corpus/core/docs/content/locales/es-ES/template-chat.mdx +1 -1
- package/corpus/core/docs/content/locales/fr-FR/cloneable-saas.mdx +2 -2
- package/corpus/core/docs/content/locales/fr-FR/faq.mdx +1 -1
- package/corpus/core/docs/content/locales/fr-FR/template-chat.mdx +1 -1
- package/corpus/core/docs/content/locales/hi-IN/cloneable-saas.mdx +2 -2
- package/corpus/core/docs/content/locales/hi-IN/faq.mdx +1 -1
- package/corpus/core/docs/content/locales/hi-IN/template-chat.mdx +1 -1
- package/corpus/core/docs/content/locales/ja-JP/cloneable-saas.mdx +2 -2
- package/corpus/core/docs/content/locales/ja-JP/faq.mdx +1 -1
- package/corpus/core/docs/content/locales/ja-JP/template-chat.mdx +1 -1
- package/corpus/core/docs/content/locales/ko-KR/cloneable-saas.mdx +2 -2
- package/corpus/core/docs/content/locales/ko-KR/faq.mdx +1 -1
- package/corpus/core/docs/content/locales/ko-KR/template-chat.mdx +1 -1
- package/corpus/core/docs/content/locales/pt-BR/cloneable-saas.mdx +2 -2
- package/corpus/core/docs/content/locales/pt-BR/faq.mdx +1 -1
- package/corpus/core/docs/content/locales/pt-BR/template-chat.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-CN/cloneable-saas.mdx +2 -2
- package/corpus/core/docs/content/locales/zh-CN/faq.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-CN/template-chat.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-TW/cloneable-saas.mdx +2 -2
- package/corpus/core/docs/content/locales/zh-TW/faq.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-TW/template-chat.mdx +1 -1
- package/corpus/core/docs/content/template-chat.mdx +1 -1
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/engine/builtin.ts +1 -1
- package/corpus/core/src/agent/engine/output-tokens.ts +1 -1
- package/corpus/core/src/agent/harness/acp-adapter.ts +28 -4
- package/corpus/core/src/agent/harness/ai-sdk-adapter.ts +3 -0
- package/corpus/core/src/agent/harness/translate.ts +3 -0
- package/corpus/core/src/agent/harness/types.ts +1 -0
- package/corpus/core/src/agent/model-config.ts +34 -13
- package/corpus/core/src/agent/production-agent.ts +87 -10
- package/corpus/core/src/agent/thread-data-builder.ts +29 -4
- package/corpus/core/src/agent/tool-call-journal.ts +109 -48
- package/corpus/core/src/agent/types.ts +6 -1
- package/corpus/core/src/cli/design-connect.ts +106 -0
- package/corpus/core/src/cli/gateway-helpers.ts +17 -0
- package/corpus/core/src/cli/recap.ts +0 -2
- package/corpus/core/src/cli/skills.ts +54 -16
- package/corpus/core/src/cli/workspace-dev.ts +29 -5
- package/corpus/core/src/client/AssistantChat.tsx +89 -42
- package/corpus/core/src/client/DefaultSpinner.tsx +8 -1
- package/corpus/core/src/client/chat/message-components.tsx +49 -1
- package/corpus/core/src/client/chat/repo-helpers.ts +71 -0
- package/corpus/core/src/client/chat/run-recovery.tsx +15 -5
- package/corpus/core/src/client/components/ApiKeySettings.tsx +8 -8
- package/corpus/core/src/client/components/CodeRequiredDialog.tsx +26 -15
- package/corpus/core/src/client/components/MissingKeyCard.tsx +13 -6
- package/corpus/core/src/client/composer/TiptapComposer.tsx +4 -3
- package/corpus/core/src/client/extensions/ExtensionsSidebarSection.tsx +0 -1
- package/corpus/core/src/client/guided-questions.tsx +21 -27
- package/corpus/core/src/client/integrations/IntegrationCard.tsx +1 -1
- package/corpus/core/src/client/integrations/IntegrationsPanel.tsx +1 -1
- package/corpus/core/src/client/onboarding/OnboardingBanner.tsx +2 -2
- package/corpus/core/src/client/onboarding/OnboardingPanel.tsx +23 -19
- package/corpus/core/src/client/resources/ResourceEditor.tsx +18 -10
- package/corpus/core/src/client/resources/ResourcesPanel.tsx +5 -1
- package/corpus/core/src/client/settings/SettingsPanel.tsx +8 -3
- package/corpus/core/src/client/settings/useBuilderStatus.ts +8 -41
- package/corpus/core/src/client/useProductionAgent.ts +6 -2
- package/corpus/core/src/deploy/build.ts +1 -1
- package/corpus/core/src/observability/traces.ts +3 -3
- package/corpus/core/src/onboarding/default-steps.ts +1 -1
- package/corpus/core/src/scripts/agent-engines/manage-agent-engine.ts +1 -1
- package/corpus/core/src/scripts/agent-engines/set-agent-engine.ts +1 -1
- package/corpus/core/src/server/agent-chat-plugin.ts +177 -81
- package/corpus/core/src/server/core-routes-plugin.ts +7 -1
- package/corpus/core/src/server/open-route.ts +59 -40
- package/corpus/core/src/shared/reasoning-effort.ts +2 -0
- package/corpus/core/src/sharing/access.ts +22 -2
- package/corpus/core/src/sharing/registry.ts +18 -0
- package/corpus/core/src/styles/agent-native.css +104 -20
- package/corpus/core/src/styles/rich-markdown-editor.css +11 -10
- package/corpus/templates/analytics/app/components/dashboard/CumulativeNetChart.tsx +10 -10
- package/corpus/templates/analytics/app/components/dashboard/RevenueChart.tsx +10 -10
- package/corpus/templates/analytics/app/components/dashboard/RevenueComparisonChart.tsx +6 -5
- package/corpus/templates/analytics/app/components/dashboard/TimeSeriesChart.tsx +9 -9
- package/corpus/templates/analytics/app/global.css +4 -0
- package/corpus/templates/analytics/app/lib/chart-theme.ts +13 -0
- package/corpus/templates/analytics/app/pages/adhoc/_shared/KpiChart.tsx +22 -24
- package/corpus/templates/analytics/changelog/2026-06-30-dashboard-charts-now-use-theme-aware-tooltip-and-grid-colors.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-30-fixed-ask-composer-spacing-so-the-chat-field-has-a-comfortab.md +6 -0
- package/corpus/templates/calendar/AGENTS.md +4 -0
- package/corpus/templates/calendar/actions/connect-google-calendar.ts +80 -0
- package/corpus/templates/calendar/changelog/2026-06-30-calendar-now-gives-the-agent-a-safe-google-connection-link-i.md +6 -0
- package/corpus/templates/calendar/server/plugins/agent-chat.ts +4 -0
- package/corpus/templates/content/app/components/editor/BubbleToolbar.tsx +5 -5
- package/corpus/templates/content/app/global.css +6 -5
- package/corpus/templates/content/changelog/2026-06-30-editor-floating-toolbars-now-use-theme-aware-colors-in-light.md +6 -0
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +6 -1
- package/corpus/templates/design/actions/add-localhost-screens.ts +63 -8
- package/corpus/templates/design/actions/apply-motion-edit.ts +12 -46
- package/corpus/templates/design/actions/list-design-native-assets.ts +2 -1
- package/corpus/templates/design/actions/migrate-board-objects-to-file.ts +49 -1
- package/corpus/templates/design/actions/navigate.ts +3 -12
- package/corpus/templates/design/actions/open-visual-edit.ts +341 -0
- package/corpus/templates/design/actions/view-screen.ts +1 -1
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +1 -1
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +345 -14
- package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +71 -91
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +25 -27
- package/corpus/templates/design/app/components/design/DeviceFrame.tsx +1 -1
- package/corpus/templates/design/app/components/design/DrawOverlay.tsx +2 -2
- package/corpus/templates/design/app/components/design/EditPanel.tsx +1111 -570
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +162 -32
- package/corpus/templates/design/app/components/design/MotionDock.tsx +268 -240
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +1038 -150
- package/corpus/templates/design/app/components/design/QuestionFlow.tsx +1 -1
- package/corpus/templates/design/app/components/design/ReviewPanel.tsx +81 -102
- package/corpus/templates/design/app/components/design/StatesPanel.tsx +6 -6
- package/corpus/templates/design/app/components/design/TokensPanel.tsx +11 -11
- package/corpus/templates/design/app/components/design/TweaksPanel.tsx +9 -7
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +1129 -155
- package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +130 -37
- package/corpus/templates/design/app/components/design/canvas-primitive-style.ts +24 -11
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +184 -162
- package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +137 -79
- package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +13 -13
- package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +8 -8
- package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +2 -2
- package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +4 -4
- package/corpus/templates/design/app/components/design/inspector/InspectorAiActions.tsx +3 -3
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +13 -7
- package/corpus/templates/design/app/components/design/inspector/ShaderControls.tsx +14 -11
- package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +4 -4
- package/corpus/templates/design/app/components/design/inspector/index.ts +2 -0
- package/corpus/templates/design/app/components/design/types.ts +19 -0
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +61 -78
- package/corpus/templates/design/app/components/layout/Header.tsx +0 -1
- package/corpus/templates/design/app/components/layout/Layout.tsx +3 -2
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +0 -2
- package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +5 -4
- package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +1 -1
- package/corpus/templates/design/app/components/visual-editor/SaveStatusIndicator.tsx +2 -2
- package/corpus/templates/design/app/global.css +56 -0
- package/corpus/templates/design/app/hooks/use-agent-generating.ts +4 -5
- package/corpus/templates/design/app/hooks/use-navigation-state.ts +6 -7
- package/corpus/templates/design/app/hooks/use-question-flow.ts +3 -2
- package/corpus/templates/design/app/hooks/useAgentEditRequest.ts +6 -4
- package/corpus/templates/design/app/i18n/zh-TW.ts +5 -14
- package/corpus/templates/design/app/i18n-data.ts +63 -188
- package/corpus/templates/design/app/lib/agent-chat.ts +13 -0
- package/corpus/templates/design/app/pages/DesignEditor.tsx +1428 -384
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +9 -5
- package/corpus/templates/design/app/pages/DesignSystems.tsx +2 -2
- package/corpus/templates/design/app/pages/Index.tsx +49 -26
- package/corpus/templates/design/app/pages/NotFound.tsx +25 -8
- package/corpus/templates/design/app/pages/VisualEdit.tsx +17 -5
- package/corpus/templates/design/app/routes/examples.tsx +1 -7
- package/corpus/templates/design/app/routes/templates.tsx +7 -4
- package/corpus/templates/design/changelog/2026-06-30-board-shapes-and-auto-layout-controls-are-clearer.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-component-selections-now-use-purple-component-chrome-and-sho.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-constraints-now-stay-tucked-into-a-compact-inspector-preview.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-creating-a-component-now-opens-in-a-compact-inspector-popove.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-cards-no-longer-show-legacy-project-type-badges.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-chat-now-keeps-new-turns-in-the-visible-design-agent-.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-editor-panels-now-keep-their-compact-text-sizing-cons.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-no-longer-shows-the-connected-local-code-warning-bann.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-now-opens-to-the-files-panel-unless-a-generation-is-a.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-opens-with-a-cleaner-empty-canvas-and-loading-preview.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-tools-use-simpler-less-decorative-icons.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-dragging-absolute-elements-no-longer-shows-coordinate-labels.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-fixed-all-screens-opening-too-zoomed-in-by-default.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-fixed-the-public-design-assets-sidebar-so-native-components-.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-fixed-the-screen-overview-board-so-empty-board-space-no-long.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-full-view-screens-can-now-scroll-while-remaining-editable.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-inspector-element-headers-show-the-selected-html-tag-and-the.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-inspector-inputs-stay-compact-across-desktop-breakpoints.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-layers-can-be-multi-selected-from-the-canvas-and-edited-toge.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-local-visual-edit-links-can-edit-localhost-frames-without-si.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-localhost-visual-edit-frames-can-now-be-selected-and-edited.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-marquee-selection-now-works-inside-screens-multi-selected-la.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-motion-is-now-available-from-the-persistent-left-rail-and-th.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-motion-timeline-collapse-and-reopen-animations-feel-smoother.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-multi-select-outlines-now-stay-consistent-across-all-screens.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-new-board-shapes-now-start-with-neutral-gray-styling.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-new-designs-open-into-a-steadier-loading-state-before-the-ed.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-new-designs-show-a-loading-state-during-handoff-and-keep-edi.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-public-visual-edit-design-links-now-open-directly-instead-of.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-removed-the-confusing-states-section-from-the-design-editor-.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-removed-the-templates-gallery-from-design-navigation.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-share-stays-visible-as-soon-as-editable-designs-load.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-signed-out-save-and-share-controls-use-simpler-labels-and-op.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-text-added-on-the-canvas-now-focuses-cleanly-with-the-right-.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-design-editor-loading-skeleton-is-simpler-and-its-bottom.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-design-editor-loading-skeleton-now-follows-the-current-t.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-design-inspector-no-longer-shows-child-layout-controls-o.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-design-inspector-no-longer-shows-the-ask-ai-section-abov.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-design-review-panel-no-longer-shows-a-separate-inline-au.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-empty-designs-page-now-focuses-on-a-single-primary-new-d.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-layers-panel-header-stays-as-layers-while-multiple-items.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-missing-design-screen-now-uses-a-neutral-back-button.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-motion-timeline-now-closes-without-squeezing-the-canvas-.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-new-design-connect-ai-setup-now-lines-up-with-the-compos.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-screen-overview-board-now-blends-into-the-canvas-and-new.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-top-level-canvas-drops-now-show-screen-guides.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-top-level-canvas-layers-now-keep-a-transparent-backdrop-and-.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-top-level-canvas-layers-now-select-reliably-from-all-screens.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-visual-edit-can-open-and-refresh-localhost-screens-in-one-au.md +6 -0
- package/corpus/templates/design/e2e/helpers.ts +15 -4
- package/corpus/templates/design/server/db/index.ts +52 -0
- package/corpus/templates/design/server/plugins/agent-chat.ts +5 -0
- package/corpus/templates/design/server/plugins/auth.ts +1 -0
- package/corpus/templates/design/server/plugins/core-routes.ts +4 -0
- package/corpus/templates/design/shared/board-file.ts +380 -5
- package/corpus/templates/design/shared/board-objects.ts +2 -2
- package/corpus/templates/design/shared/code-layer.ts +50 -6
- package/corpus/templates/design/shared/motion-compiler.ts +27 -0
- package/corpus/templates/macros/app/components/DailyProgress.tsx +41 -37
- package/corpus/templates/macros/app/components/ExerciseCard.tsx +2 -2
- package/corpus/templates/macros/app/components/MealCard.tsx +2 -2
- package/corpus/templates/macros/app/components/VoiceDictation.tsx +1 -1
- package/corpus/templates/macros/app/components/WeeklyCaloriesChart.tsx +1 -1
- package/corpus/templates/macros/app/components/WeightCard.tsx +2 -2
- package/corpus/templates/macros/app/components/WeightTracker.tsx +1 -1
- package/corpus/templates/macros/app/components/layout/AppLayout.tsx +1 -1
- package/corpus/templates/macros/app/routes/_index.tsx +5 -5
- package/corpus/templates/macros/app/routes/analytics.tsx +1 -1
- package/corpus/templates/macros/changelog/2026-06-30-dashboard-loading-and-chart-surfaces-now-use-theme-aware-col.md +6 -0
- package/corpus/templates/mail/app/components/email/ComposeBubbleToolbar.tsx +14 -11
- package/corpus/templates/mail/app/global.css +3 -2
- package/corpus/templates/mail/changelog/2026-06-30-compose-floating-toolbars-now-use-theme-aware-colors-in-ligh.md +6 -0
- package/corpus/templates/plan/app/pages/PlansPage.tsx +2 -2
- package/corpus/templates/slides/app/components/deck/DeckCard.tsx +3 -3
- package/corpus/templates/slides/app/global.css +10 -0
- package/corpus/templates/slides/app/pages/Index.tsx +55 -51
- package/corpus/templates/slides/changelog/2026-06-30-deck-thumbnails-collapse-cleanly-to-one-column-when-the-chat.md +6 -0
- package/dist/agent/engine/anthropic-engine.d.ts +2 -2
- package/dist/agent/engine/anthropic-engine.d.ts.map +1 -1
- package/dist/agent/engine/builder-engine.d.ts +2 -2
- package/dist/agent/engine/builder-engine.d.ts.map +1 -1
- package/dist/agent/engine/builtin.js +1 -1
- package/dist/agent/engine/builtin.js.map +1 -1
- package/dist/agent/engine/output-tokens.js +1 -1
- package/dist/agent/engine/output-tokens.js.map +1 -1
- package/dist/agent/harness/acp-adapter.d.ts +4 -1
- package/dist/agent/harness/acp-adapter.d.ts.map +1 -1
- package/dist/agent/harness/acp-adapter.js +19 -2
- package/dist/agent/harness/acp-adapter.js.map +1 -1
- package/dist/agent/harness/ai-sdk-adapter.d.ts.map +1 -1
- package/dist/agent/harness/ai-sdk-adapter.js +3 -0
- package/dist/agent/harness/ai-sdk-adapter.js.map +1 -1
- package/dist/agent/harness/translate.d.ts.map +1 -1
- package/dist/agent/harness/translate.js +3 -0
- package/dist/agent/harness/translate.js.map +1 -1
- package/dist/agent/harness/types.d.ts +1 -0
- package/dist/agent/harness/types.d.ts.map +1 -1
- package/dist/agent/harness/types.js.map +1 -1
- package/dist/agent/model-config.d.ts +21 -20
- package/dist/agent/model-config.d.ts.map +1 -1
- package/dist/agent/model-config.js +31 -13
- package/dist/agent/model-config.js.map +1 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +85 -10
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/thread-data-builder.d.ts.map +1 -1
- package/dist/agent/thread-data-builder.js +27 -6
- package/dist/agent/thread-data-builder.js.map +1 -1
- package/dist/agent/tool-call-journal.d.ts +11 -9
- package/dist/agent/tool-call-journal.d.ts.map +1 -1
- package/dist/agent/tool-call-journal.js +92 -40
- package/dist/agent/tool-call-journal.js.map +1 -1
- package/dist/agent/types.d.ts +5 -1
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/cli/design-connect.d.ts.map +1 -1
- package/dist/cli/design-connect.js +84 -0
- package/dist/cli/design-connect.js.map +1 -1
- package/dist/cli/gateway-helpers.d.ts +4 -0
- package/dist/cli/gateway-helpers.d.ts.map +1 -1
- package/dist/cli/gateway-helpers.js +9 -0
- package/dist/cli/gateway-helpers.js.map +1 -1
- package/dist/cli/recap.d.ts.map +1 -1
- package/dist/cli/recap.js +0 -2
- package/dist/cli/recap.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +54 -16
- package/dist/cli/skills.js.map +1 -1
- package/dist/cli/workspace-dev.d.ts.map +1 -1
- package/dist/cli/workspace-dev.js +33 -6
- package/dist/cli/workspace-dev.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +72 -26
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/DefaultSpinner.d.ts.map +1 -1
- package/dist/client/DefaultSpinner.js +8 -1
- package/dist/client/DefaultSpinner.js.map +1 -1
- package/dist/client/chat/message-components.d.ts +7 -1
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +37 -1
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/chat/repo-helpers.d.ts +1 -0
- package/dist/client/chat/repo-helpers.d.ts.map +1 -1
- package/dist/client/chat/repo-helpers.js +59 -0
- package/dist/client/chat/repo-helpers.js.map +1 -1
- package/dist/client/chat/run-recovery.d.ts.map +1 -1
- package/dist/client/chat/run-recovery.js +4 -4
- package/dist/client/chat/run-recovery.js.map +1 -1
- package/dist/client/components/ApiKeySettings.js +8 -8
- package/dist/client/components/ApiKeySettings.js.map +1 -1
- package/dist/client/components/CodeRequiredDialog.d.ts.map +1 -1
- package/dist/client/components/CodeRequiredDialog.js +24 -15
- package/dist/client/components/CodeRequiredDialog.js.map +1 -1
- package/dist/client/components/MissingKeyCard.d.ts.map +1 -1
- package/dist/client/components/MissingKeyCard.js +11 -6
- package/dist/client/components/MissingKeyCard.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +4 -3
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/extensions/ExtensionsSidebarSection.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionsSidebarSection.js +1 -1
- package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -1
- package/dist/client/guided-questions.d.ts.map +1 -1
- package/dist/client/guided-questions.js +6 -6
- package/dist/client/guided-questions.js.map +1 -1
- package/dist/client/integrations/IntegrationCard.js +1 -1
- package/dist/client/integrations/IntegrationCard.js.map +1 -1
- package/dist/client/integrations/IntegrationsPanel.js +1 -1
- package/dist/client/integrations/IntegrationsPanel.js.map +1 -1
- package/dist/client/onboarding/OnboardingBanner.js +2 -2
- package/dist/client/onboarding/OnboardingBanner.js.map +1 -1
- package/dist/client/onboarding/OnboardingPanel.js +23 -19
- package/dist/client/onboarding/OnboardingPanel.js.map +1 -1
- package/dist/client/resources/ResourceEditor.d.ts.map +1 -1
- package/dist/client/resources/ResourceEditor.js +13 -10
- package/dist/client/resources/ResourceEditor.js.map +1 -1
- package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
- package/dist/client/resources/ResourcesPanel.js +2 -1
- package/dist/client/resources/ResourcesPanel.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +8 -3
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
- package/dist/client/settings/useBuilderStatus.js +6 -38
- package/dist/client/settings/useBuilderStatus.js.map +1 -1
- package/dist/client/useProductionAgent.d.ts +2 -1
- package/dist/client/useProductionAgent.d.ts.map +1 -1
- package/dist/client/useProductionAgent.js.map +1 -1
- package/dist/deploy/build.js +1 -1
- package/dist/deploy/build.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/observability/traces.d.ts.map +1 -1
- package/dist/observability/traces.js.map +1 -1
- package/dist/onboarding/default-steps.js +1 -1
- package/dist/onboarding/default-steps.js.map +1 -1
- package/dist/scripts/agent-engines/manage-agent-engine.js +1 -1
- package/dist/scripts/agent-engines/manage-agent-engine.js.map +1 -1
- package/dist/scripts/agent-engines/set-agent-engine.js +1 -1
- package/dist/scripts/agent-engines/set-agent-engine.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +3 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +134 -72
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts +3 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +4 -1
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/open-route.d.ts +9 -0
- package/dist/server/open-route.d.ts.map +1 -1
- package/dist/server/open-route.js +48 -38
- package/dist/server/open-route.js.map +1 -1
- package/dist/shared/reasoning-effort.js +3 -0
- package/dist/shared/reasoning-effort.js.map +1 -1
- package/dist/sharing/access.d.ts.map +1 -1
- package/dist/sharing/access.js +18 -2
- package/dist/sharing/access.js.map +1 -1
- package/dist/sharing/registry.d.ts +10 -0
- package/dist/sharing/registry.d.ts.map +1 -1
- package/dist/sharing/registry.js.map +1 -1
- package/dist/styles/agent-native.css +104 -20
- package/dist/styles/rich-markdown-editor.css +11 -10
- package/docs/content/cloneable-saas.mdx +2 -2
- package/docs/content/faq.mdx +1 -1
- package/docs/content/locales/ar-SA/cloneable-saas.mdx +2 -2
- package/docs/content/locales/ar-SA/faq.mdx +1 -1
- package/docs/content/locales/ar-SA/template-chat.mdx +1 -1
- package/docs/content/locales/de-DE/cloneable-saas.mdx +2 -2
- package/docs/content/locales/de-DE/faq.mdx +1 -1
- package/docs/content/locales/de-DE/template-chat.mdx +1 -1
- package/docs/content/locales/es-ES/cloneable-saas.mdx +2 -2
- package/docs/content/locales/es-ES/faq.mdx +1 -1
- package/docs/content/locales/es-ES/template-chat.mdx +1 -1
- package/docs/content/locales/fr-FR/cloneable-saas.mdx +2 -2
- package/docs/content/locales/fr-FR/faq.mdx +1 -1
- package/docs/content/locales/fr-FR/template-chat.mdx +1 -1
- package/docs/content/locales/hi-IN/cloneable-saas.mdx +2 -2
- package/docs/content/locales/hi-IN/faq.mdx +1 -1
- package/docs/content/locales/hi-IN/template-chat.mdx +1 -1
- package/docs/content/locales/ja-JP/cloneable-saas.mdx +2 -2
- package/docs/content/locales/ja-JP/faq.mdx +1 -1
- package/docs/content/locales/ja-JP/template-chat.mdx +1 -1
- package/docs/content/locales/ko-KR/cloneable-saas.mdx +2 -2
- package/docs/content/locales/ko-KR/faq.mdx +1 -1
- package/docs/content/locales/ko-KR/template-chat.mdx +1 -1
- package/docs/content/locales/pt-BR/cloneable-saas.mdx +2 -2
- package/docs/content/locales/pt-BR/faq.mdx +1 -1
- package/docs/content/locales/pt-BR/template-chat.mdx +1 -1
- package/docs/content/locales/zh-CN/cloneable-saas.mdx +2 -2
- package/docs/content/locales/zh-CN/faq.mdx +1 -1
- package/docs/content/locales/zh-CN/template-chat.mdx +1 -1
- package/docs/content/locales/zh-TW/cloneable-saas.mdx +2 -2
- package/docs/content/locales/zh-TW/faq.mdx +1 -1
- package/docs/content/locales/zh-TW/template-chat.mdx +1 -1
- package/docs/content/template-chat.mdx +1 -1
- package/package.json +1 -1
- package/corpus/templates/design/app/components/design/LocalSourceEditBanner.tsx +0 -157
- package/corpus/templates/design/app/lib/design-templates.ts +0 -1305
- package/corpus/templates/design/app/pages/Templates.tsx +0 -279
|
@@ -8,16 +8,18 @@
|
|
|
8
8
|
* told about any tool call that started but whose outcome was never recorded.
|
|
9
9
|
*
|
|
10
10
|
* IMPORTANT — this is a pure read-over-the-ledger view. There is no new
|
|
11
|
-
* recording hook anywhere in the hot path.
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* recording hook anywhere in the hot path. Classification uses input-aware
|
|
12
|
+
* `tool_start` → `tool_done` matching when a `tool_done` event carries its
|
|
13
|
+
* input, while preserving the legacy positional fallback that older ledger
|
|
14
|
+
* events and `thread-data-builder.ts` rely on:
|
|
14
15
|
*
|
|
15
16
|
* - `tool_start` events carry `{ tool, input }` (no tool-call id at this
|
|
16
17
|
* layer; the ledger event stream omits it).
|
|
17
|
-
* - `tool_done` events carry `{ tool, result }`.
|
|
18
|
-
* - A `tool_done` is matched to the
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* - `tool_done` events carry `{ tool, input?, result }`.
|
|
19
|
+
* - A `tool_done` with input is matched to the open start with the same tool
|
|
20
|
+
* name and deep-canonicalized input.
|
|
21
|
+
* - A legacy `tool_done` without input is matched to the OLDEST still-open
|
|
22
|
+
* `tool_start` for the same tool name (FIFO per tool).
|
|
21
23
|
*
|
|
22
24
|
* A `tool_start` with no matching `tool_done` is the dangerous case: the call
|
|
23
25
|
* began, its side effect may or may not have landed, and the interruption ate
|
|
@@ -32,7 +34,7 @@
|
|
|
32
34
|
* effect again. Layer 2 is the stronger guarantee.
|
|
33
35
|
*/
|
|
34
36
|
|
|
35
|
-
import type { AgentChatEvent } from "./types.js";
|
|
37
|
+
import type { AgentChatEvent, AgentToolInput } from "./types.js";
|
|
36
38
|
|
|
37
39
|
/** A single recorded tool-call ledger entry, classified by outcome. */
|
|
38
40
|
export interface ToolCallJournalEntry {
|
|
@@ -46,7 +48,7 @@ export interface ToolCallJournalEntry {
|
|
|
46
48
|
/** Tool / action name (from the `tool_start` event). */
|
|
47
49
|
tool: string;
|
|
48
50
|
/** Tool input captured at `tool_start`, if any. */
|
|
49
|
-
input?:
|
|
51
|
+
input?: AgentToolInput;
|
|
50
52
|
/** 0-based position of the `tool_start` among all tool calls in the turn. */
|
|
51
53
|
order: number;
|
|
52
54
|
/** Result text from the matched `tool_done`, when the call completed. */
|
|
@@ -70,22 +72,53 @@ const INPUT_SIGNATURE_MAX_CHARS = 120;
|
|
|
70
72
|
/** Max length of a per-tool-call result summary surfaced in the resume note. */
|
|
71
73
|
const RESULT_SUMMARY_MAX_CHARS = 400;
|
|
72
74
|
|
|
73
|
-
function inputSignature(input:
|
|
74
|
-
if (
|
|
75
|
-
let sig: string;
|
|
75
|
+
function inputSignature(input: unknown): string {
|
|
76
|
+
if (input == null) return "";
|
|
76
77
|
try {
|
|
77
|
-
|
|
78
|
-
// regardless of how the engine serialized the object.
|
|
79
|
-
const sorted = Object.keys(input)
|
|
80
|
-
.sort()
|
|
81
|
-
.reduce<Record<string, string>>((acc, k) => {
|
|
82
|
-
acc[k] = input[k];
|
|
83
|
-
return acc;
|
|
84
|
-
}, {});
|
|
85
|
-
sig = JSON.stringify(sorted);
|
|
78
|
+
return JSON.stringify(canonicalizeForSignature(input));
|
|
86
79
|
} catch {
|
|
87
|
-
|
|
80
|
+
return String(input);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function canonicalizeForSignature(
|
|
85
|
+
input: unknown,
|
|
86
|
+
seen = new WeakSet(),
|
|
87
|
+
): unknown {
|
|
88
|
+
if (input == null) return input;
|
|
89
|
+
if (typeof input === "bigint") return input.toString();
|
|
90
|
+
if (typeof input === "function" || typeof input === "symbol") {
|
|
91
|
+
return String(input);
|
|
92
|
+
}
|
|
93
|
+
if (typeof input !== "object") return input;
|
|
94
|
+
|
|
95
|
+
if (seen.has(input)) return "[Circular]";
|
|
96
|
+
seen.add(input);
|
|
97
|
+
if (Array.isArray(input)) {
|
|
98
|
+
const output = input.map((value) =>
|
|
99
|
+
value === undefined
|
|
100
|
+
? "[Undefined]"
|
|
101
|
+
: canonicalizeForSignature(value, seen),
|
|
102
|
+
);
|
|
103
|
+
seen.delete(input);
|
|
104
|
+
return output;
|
|
88
105
|
}
|
|
106
|
+
|
|
107
|
+
const object = input as Record<string, unknown>;
|
|
108
|
+
const output: Record<string, unknown> = {};
|
|
109
|
+
for (const key of Object.keys(object).sort()) {
|
|
110
|
+
const value = object[key];
|
|
111
|
+
output[key] =
|
|
112
|
+
value === undefined
|
|
113
|
+
? "[Undefined]"
|
|
114
|
+
: canonicalizeForSignature(value, seen);
|
|
115
|
+
}
|
|
116
|
+
seen.delete(input);
|
|
117
|
+
return output;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function displayInputSignature(input: unknown): string {
|
|
121
|
+
const sig = inputSignature(input);
|
|
89
122
|
return sig.length > INPUT_SIGNATURE_MAX_CHARS
|
|
90
123
|
? sig.slice(0, INPUT_SIGNATURE_MAX_CHARS)
|
|
91
124
|
: sig;
|
|
@@ -101,10 +134,9 @@ function inputSignature(input: Record<string, string> | undefined): string {
|
|
|
101
134
|
export function classifyToolCallJournal(
|
|
102
135
|
events: readonly AgentChatEvent[],
|
|
103
136
|
): ToolCallJournal {
|
|
104
|
-
// Open tool_start entries awaiting a matching tool_done
|
|
105
|
-
//
|
|
106
|
-
//
|
|
107
|
-
// first unmatched start of a given name is the one this done belongs to.
|
|
137
|
+
// Open tool_start entries awaiting a matching tool_done. We index by tool
|
|
138
|
+
// name first, then prefer matching input signatures when the done event
|
|
139
|
+
// carries input. Older ledger entries without done input fall back to FIFO.
|
|
108
140
|
const openByTool = new Map<string, ToolCallJournalEntry[]>();
|
|
109
141
|
const completed: ToolCallJournalEntry[] = [];
|
|
110
142
|
let order = 0;
|
|
@@ -119,11 +151,9 @@ export function classifyToolCallJournal(
|
|
|
119
151
|
|
|
120
152
|
if (event.type === "tool_start") {
|
|
121
153
|
const tool = event.tool ?? "unknown";
|
|
122
|
-
const input =
|
|
123
|
-
| Record<string, string>
|
|
124
|
-
| undefined;
|
|
154
|
+
const input = event.input ?? undefined;
|
|
125
155
|
const entry: ToolCallJournalEntry = {
|
|
126
|
-
key: `${tool}#${order}:${
|
|
156
|
+
key: `${tool}#${order}:${displayInputSignature(input)}`,
|
|
127
157
|
tool,
|
|
128
158
|
...(input ? { input } : {}),
|
|
129
159
|
order,
|
|
@@ -138,8 +168,14 @@ export function classifyToolCallJournal(
|
|
|
138
168
|
if (event.type === "tool_done") {
|
|
139
169
|
const tool = event.tool ?? "unknown";
|
|
140
170
|
const queue = openByTool.get(tool);
|
|
141
|
-
const entry = queue
|
|
171
|
+
const entry = takeMatchingOpenEntry(queue, event);
|
|
142
172
|
if (entry) {
|
|
173
|
+
if (isNonCompletedToolDone(event)) {
|
|
174
|
+
// Failed/blocked calls reached a terminal tool_done, but their side
|
|
175
|
+
// effect did not complete. Drop the matching start instead of
|
|
176
|
+
// classifying it as completed or interrupted.
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
143
179
|
entry.result = event.result ?? "";
|
|
144
180
|
completed.push(entry);
|
|
145
181
|
}
|
|
@@ -159,6 +195,45 @@ export function classifyToolCallJournal(
|
|
|
159
195
|
return { completed, interrupted };
|
|
160
196
|
}
|
|
161
197
|
|
|
198
|
+
function takeMatchingOpenEntry(
|
|
199
|
+
queue: ToolCallJournalEntry[] | undefined,
|
|
200
|
+
event: Extract<AgentChatEvent, { type: "tool_done" }>,
|
|
201
|
+
): ToolCallJournalEntry | undefined {
|
|
202
|
+
if (!queue || queue.length === 0) return undefined;
|
|
203
|
+
if (event.input !== undefined) {
|
|
204
|
+
const doneSig = inputSignature(event.input);
|
|
205
|
+
const index = queue.findIndex(
|
|
206
|
+
(entry) => inputSignature(entry.input) === doneSig,
|
|
207
|
+
);
|
|
208
|
+
if (index >= 0) return queue.splice(index, 1)[0];
|
|
209
|
+
}
|
|
210
|
+
return queue.shift();
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function isNonCompletedToolDone(
|
|
214
|
+
event: Extract<AgentChatEvent, { type: "tool_done" }>,
|
|
215
|
+
): boolean {
|
|
216
|
+
if (event.completedSideEffect === false) return true;
|
|
217
|
+
if (event.isError === true) return true;
|
|
218
|
+
|
|
219
|
+
const result = (event.result ?? "").trim();
|
|
220
|
+
if (!result) return false;
|
|
221
|
+
|
|
222
|
+
// Legacy run events did not persist isError. Keep known non-execution results
|
|
223
|
+
// from becoming durable "completed" write calls after deploy.
|
|
224
|
+
return (
|
|
225
|
+
result.startsWith("Error: Unknown tool") ||
|
|
226
|
+
result.startsWith("Error running ") ||
|
|
227
|
+
result.startsWith("Invalid action parameters for ") ||
|
|
228
|
+
result.startsWith("Plan mode blocked ") ||
|
|
229
|
+
result.startsWith("Skipped ") ||
|
|
230
|
+
result.startsWith("Stopped after ") ||
|
|
231
|
+
result.startsWith("The tool was not executed") ||
|
|
232
|
+
result.startsWith("Awaiting human approval") ||
|
|
233
|
+
result.includes(" did NOT execute")
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
|
|
162
237
|
/** True when the journal has nothing worth telling a resuming model about. */
|
|
163
238
|
export function isJournalEmpty(journal: ToolCallJournal): boolean {
|
|
164
239
|
return journal.completed.length === 0 && journal.interrupted.length === 0;
|
|
@@ -184,7 +259,7 @@ export function findCompletedJournalEntry(
|
|
|
184
259
|
input: unknown,
|
|
185
260
|
consumedKeys?: Set<string>,
|
|
186
261
|
): ToolCallJournalEntry | undefined {
|
|
187
|
-
const wantSig = inputSignature(
|
|
262
|
+
const wantSig = inputSignature(input);
|
|
188
263
|
for (const entry of journal.completed) {
|
|
189
264
|
if (entry.tool !== toolName) continue;
|
|
190
265
|
if (inputSignature(entry.input) !== wantSig) continue;
|
|
@@ -195,20 +270,6 @@ export function findCompletedJournalEntry(
|
|
|
195
270
|
return undefined;
|
|
196
271
|
}
|
|
197
272
|
|
|
198
|
-
/**
|
|
199
|
-
* Coerce an arbitrary tool input into the `Record<string, string>` shape the
|
|
200
|
-
* journal recorded at `tool_start` so signatures compare apples-to-apples. The
|
|
201
|
-
* ledger stores `tool_start.input` as a string map; the live call's `input` is
|
|
202
|
-
* the parsed object — both pass through `inputSignature`, which sorts keys and
|
|
203
|
-
* JSON-stringifies, so a plain object compares correctly.
|
|
204
|
-
*/
|
|
205
|
-
function normalizeInputForSignature(
|
|
206
|
-
input: unknown,
|
|
207
|
-
): Record<string, string> | undefined {
|
|
208
|
-
if (input == null || typeof input !== "object") return undefined;
|
|
209
|
-
return input as Record<string, string>;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
273
|
function summarizeResult(result: string | undefined): string {
|
|
213
274
|
if (!result) return "(no result recorded)";
|
|
214
275
|
const oneLine = result.replace(/\s+/g, " ").trim();
|
|
@@ -218,9 +279,9 @@ function summarizeResult(result: string | undefined): string {
|
|
|
218
279
|
: oneLine;
|
|
219
280
|
}
|
|
220
281
|
|
|
221
|
-
function describeInput(input:
|
|
282
|
+
function describeInput(input: unknown): string {
|
|
222
283
|
if (!input) return "";
|
|
223
|
-
const sig =
|
|
284
|
+
const sig = displayInputSignature(input);
|
|
224
285
|
return sig && sig !== "{}" ? ` input: ${sig}` : "";
|
|
225
286
|
}
|
|
226
287
|
|
|
@@ -207,16 +207,21 @@ export interface AgentChatRequest {
|
|
|
207
207
|
approvedToolCalls?: string[];
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
+
export type AgentToolInput = Record<string, unknown>;
|
|
211
|
+
|
|
210
212
|
export type AgentChatEvent =
|
|
211
213
|
| { type: "text"; text: string }
|
|
212
214
|
| { type: "thinking"; text: string }
|
|
213
215
|
| { type: "activity"; label: string; tool?: string }
|
|
214
216
|
| { type: "stream_keepalive" }
|
|
215
|
-
| { type: "tool_start"; tool: string; input:
|
|
217
|
+
| { type: "tool_start"; tool: string; input: AgentToolInput }
|
|
216
218
|
| {
|
|
217
219
|
type: "tool_done";
|
|
218
220
|
tool: string;
|
|
221
|
+
input?: AgentToolInput;
|
|
219
222
|
result: string;
|
|
223
|
+
isError?: boolean;
|
|
224
|
+
completedSideEffect?: boolean;
|
|
220
225
|
mcpApp?: AgentMcpAppPayload;
|
|
221
226
|
chatUI?: ActionChatUIConfig;
|
|
222
227
|
}
|
|
@@ -402,6 +402,78 @@ function sendJson(
|
|
|
402
402
|
res.end(`${JSON.stringify(body, null, 2)}\n`);
|
|
403
403
|
}
|
|
404
404
|
|
|
405
|
+
function sameOrigin(a: string, b: string): boolean {
|
|
406
|
+
try {
|
|
407
|
+
return new URL(a).origin === new URL(b).origin;
|
|
408
|
+
} catch {
|
|
409
|
+
return false;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function resolvePreviewSnapshotUrl(
|
|
414
|
+
devServerUrl: string,
|
|
415
|
+
rawUrl: string | null,
|
|
416
|
+
): string {
|
|
417
|
+
const base = normalizeHttpUrl(devServerUrl);
|
|
418
|
+
const parsed = new URL(rawUrl?.trim() || "/", `${base}/`);
|
|
419
|
+
parsed.hash = "";
|
|
420
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
421
|
+
throw new Error("Snapshot URL must use http(s).");
|
|
422
|
+
}
|
|
423
|
+
if (!sameOrigin(parsed.toString(), base)) {
|
|
424
|
+
throw new Error("Snapshot URL must stay on the connected dev server.");
|
|
425
|
+
}
|
|
426
|
+
return parsed.toString();
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
async function fetchPreviewSnapshot(
|
|
430
|
+
devServerUrl: string,
|
|
431
|
+
targetUrl: string,
|
|
432
|
+
redirects = 0,
|
|
433
|
+
): Promise<{
|
|
434
|
+
url: string;
|
|
435
|
+
status: number;
|
|
436
|
+
contentType: string;
|
|
437
|
+
html: string;
|
|
438
|
+
}> {
|
|
439
|
+
if (redirects > 5) {
|
|
440
|
+
throw new Error("Too many redirects while fetching preview snapshot.");
|
|
441
|
+
}
|
|
442
|
+
const controller = new AbortController();
|
|
443
|
+
const timeout = setTimeout(() => controller.abort(), 10_000);
|
|
444
|
+
try {
|
|
445
|
+
const response = await fetch(targetUrl, {
|
|
446
|
+
method: "GET",
|
|
447
|
+
redirect: "manual",
|
|
448
|
+
signal: controller.signal,
|
|
449
|
+
headers: {
|
|
450
|
+
accept: "text/html,application/xhtml+xml;q=0.9,*/*;q=0.8",
|
|
451
|
+
},
|
|
452
|
+
});
|
|
453
|
+
const location = response.headers.get("location");
|
|
454
|
+
if (location && response.status >= 300 && response.status < 400) {
|
|
455
|
+
const redirected = new URL(location, targetUrl);
|
|
456
|
+
redirected.hash = "";
|
|
457
|
+
if (!sameOrigin(redirected.toString(), devServerUrl)) {
|
|
458
|
+
throw new Error("Snapshot redirect left the connected dev server.");
|
|
459
|
+
}
|
|
460
|
+
return fetchPreviewSnapshot(
|
|
461
|
+
devServerUrl,
|
|
462
|
+
redirected.toString(),
|
|
463
|
+
redirects + 1,
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
return {
|
|
467
|
+
url: response.url || targetUrl,
|
|
468
|
+
status: response.status,
|
|
469
|
+
contentType: response.headers.get("content-type") ?? "",
|
|
470
|
+
html: await response.text(),
|
|
471
|
+
};
|
|
472
|
+
} finally {
|
|
473
|
+
clearTimeout(timeout);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
405
477
|
/** Read the full request body as a UTF-8 string. */
|
|
406
478
|
async function readRequestBody(req: IncomingMessage): Promise<string> {
|
|
407
479
|
return new Promise<string>((resolve, reject) => {
|
|
@@ -514,6 +586,40 @@ export async function startDesignConnectBridge(
|
|
|
514
586
|
sendJson(res, 200, { ok: true, source: manifest.source });
|
|
515
587
|
return;
|
|
516
588
|
}
|
|
589
|
+
if (pathname === "/snapshot") {
|
|
590
|
+
if (req.method !== "GET") {
|
|
591
|
+
sendJson(res, 405, { ok: false, error: "method not allowed" });
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
void (async () => {
|
|
595
|
+
try {
|
|
596
|
+
const requestUrl = new URL(req.url ?? "/", manifest.bridgeUrl);
|
|
597
|
+
const targetUrl = resolvePreviewSnapshotUrl(
|
|
598
|
+
manifest.devServerUrl,
|
|
599
|
+
requestUrl.searchParams.get("url") ??
|
|
600
|
+
requestUrl.searchParams.get("path"),
|
|
601
|
+
);
|
|
602
|
+
const snapshot = await fetchPreviewSnapshot(
|
|
603
|
+
manifest.devServerUrl,
|
|
604
|
+
targetUrl,
|
|
605
|
+
);
|
|
606
|
+
sendJson(res, snapshot.status >= 400 ? snapshot.status : 200, {
|
|
607
|
+
ok: snapshot.status < 400,
|
|
608
|
+
source: manifest.source,
|
|
609
|
+
url: snapshot.url,
|
|
610
|
+
status: snapshot.status,
|
|
611
|
+
contentType: snapshot.contentType,
|
|
612
|
+
html: snapshot.html,
|
|
613
|
+
});
|
|
614
|
+
} catch (err: unknown) {
|
|
615
|
+
sendJson(res, 400, {
|
|
616
|
+
ok: false,
|
|
617
|
+
error: err instanceof Error ? err.message : String(err),
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
})();
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
517
623
|
|
|
518
624
|
// ── Token-gated write endpoints (POST only) ───────────────────────────
|
|
519
625
|
|
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
import type { EventEmitter } from "node:events";
|
|
2
|
+
|
|
3
|
+
type ErrorEventEmitter = Pick<EventEmitter, "on"> & object;
|
|
4
|
+
|
|
5
|
+
const gatewaySocketsWithErrorSink = new WeakSet<object>();
|
|
6
|
+
|
|
7
|
+
export function attachGatewaySocketErrorSink(
|
|
8
|
+
socket: ErrorEventEmitter | null | undefined,
|
|
9
|
+
onError?: (error: unknown) => void,
|
|
10
|
+
): void {
|
|
11
|
+
if (!socket || gatewaySocketsWithErrorSink.has(socket)) return;
|
|
12
|
+
gatewaySocketsWithErrorSink.add(socket);
|
|
13
|
+
socket.on("error", (error) => {
|
|
14
|
+
onError?.(error);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
1
18
|
/**
|
|
2
19
|
* When an app returns a redirect to a root-relative path that doesn't already
|
|
3
20
|
* include the app prefix, prepend it. This handles the common case where a
|
|
@@ -1995,7 +1995,6 @@ export function buildCommentBody(env: NodeJS.ProcessEnv = process.env): string {
|
|
|
1995
1995
|
|
|
1996
1996
|
lines.push(`Here's a [visual recap](${safeUrl}) of what changed:`);
|
|
1997
1997
|
lines.push("");
|
|
1998
|
-
lines.push(`<a href="${safeUrl}">`);
|
|
1999
1998
|
lines.push(`<picture>`);
|
|
2000
1999
|
if (lightImageUrl && darkImageUrl) {
|
|
2001
2000
|
lines.push(
|
|
@@ -2004,7 +2003,6 @@ export function buildCommentBody(env: NodeJS.ProcessEnv = process.env): string {
|
|
|
2004
2003
|
}
|
|
2005
2004
|
lines.push(` <img alt="Visual recap" src="${fallbackImageUrl}">`);
|
|
2006
2005
|
lines.push(`</picture>`);
|
|
2007
|
-
lines.push(`</a>`);
|
|
2008
2006
|
lines.push("");
|
|
2009
2007
|
lines.push(`**Open the [full interactive recap](${safeUrl})**`);
|
|
2010
2008
|
if (env.DIFF_HUGE === "true") {
|
|
@@ -449,6 +449,10 @@ iframe-backed screens on the infinite canvas.
|
|
|
449
449
|
- The \`/visual-edit\` entry route can open before the viewer signs in. Public
|
|
450
450
|
\`/design/:id\` editor links can also render read-only public designs without a
|
|
451
451
|
session.
|
|
452
|
+
- Prefer links returned by Design actions or \`/_agent-native/open\` deep links.
|
|
453
|
+
Do not surface URLs with \`_session=\` tokens. Query sessions are only a
|
|
454
|
+
fallback after normal cookie resolution, so an existing browser session can
|
|
455
|
+
still open the design as a different user and show "Design not found".
|
|
452
456
|
- Do not attempt anonymous write actions. Bridge registration, design creation,
|
|
453
457
|
screen placement, generation, saving, and sharing are account-backed. If a
|
|
454
458
|
signed-out visitor wants to save or share, send them through the framework
|
|
@@ -471,30 +475,44 @@ For one-shot agent setup, ask for JSON and keep the long-running bridge open in
|
|
|
471
475
|
a second terminal if the user needs live updates:
|
|
472
476
|
|
|
473
477
|
\`\`\`bash
|
|
474
|
-
npx @agent-native/core@latest design connect --url http://localhost:5173 --root .
|
|
478
|
+
npx @agent-native/core@latest design connect --url http://localhost:5173 --root .
|
|
479
|
+
curl http://127.0.0.1:7331/manifest.json
|
|
475
480
|
\`\`\`
|
|
476
481
|
|
|
482
|
+
Do not use \`--json\` for an editable session. \`--json\`, \`--once\`, and
|
|
483
|
+
\`--dry-run\` print the manifest and exit, so Design will fall back to a
|
|
484
|
+
non-editable live iframe as soon as it tries to refresh the snapshot.
|
|
485
|
+
|
|
477
486
|
## Action Flow
|
|
478
487
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
488
|
+
Prefer the single authenticated \`open-visual-edit\` action. It registers or
|
|
489
|
+
refreshes the localhost bridge, creates or reuses a Design project, places
|
|
490
|
+
URL-backed screens, stores the active visual-edit context, and navigates to
|
|
491
|
+
overview mode in one call. This avoids creating a private design under a
|
|
492
|
+
synthetic CLI user and then handing the browser a tokenized URL that may be
|
|
493
|
+
shadowed by an existing session.
|
|
483
494
|
|
|
484
495
|
\`\`\`bash
|
|
485
|
-
pnpm action
|
|
486
|
-
"
|
|
487
|
-
"
|
|
496
|
+
pnpm action open-visual-edit '{
|
|
497
|
+
"title": "Docs homepage visual edit",
|
|
498
|
+
"devServerUrl": "http://localhost:5173",
|
|
499
|
+
"bridgeUrl": "http://127.0.0.1:7331",
|
|
500
|
+
"rootPath": "/absolute/path/to/app",
|
|
501
|
+
"routeManifest": { "...": "from /manifest.json" },
|
|
488
502
|
"paths": ["/", "/pricing", "/checkout?step=payment"]
|
|
489
503
|
}'
|
|
490
504
|
\`\`\`
|
|
491
505
|
|
|
506
|
+
The action returns \`designId\`, \`connectionId\`, \`screens\`, \`urlPath\`, and
|
|
507
|
+
\`openUrl\`. Keep those IDs in the chat context for follow-ups.
|
|
508
|
+
|
|
492
509
|
For a numbered flow the user describes in chat, keep the labels and order:
|
|
493
510
|
|
|
494
511
|
\`\`\`bash
|
|
495
|
-
pnpm action
|
|
496
|
-
"designId": "<design-id>",
|
|
497
|
-
"connectionId": "<connection-id>",
|
|
512
|
+
pnpm action open-visual-edit '{
|
|
513
|
+
"designId": "<existing-design-id>",
|
|
514
|
+
"connectionId": "<existing-connection-id>",
|
|
515
|
+
"devServerUrl": "http://localhost:1234",
|
|
498
516
|
"routes": [
|
|
499
517
|
{ "url": "localhost:1234/onboarding/1", "title": "Screen 1" },
|
|
500
518
|
{ "url": "localhost:1234/onboarding/2", "title": "Screen 2" },
|
|
@@ -503,21 +521,41 @@ pnpm action add-localhost-screens '{
|
|
|
503
521
|
}'
|
|
504
522
|
\`\`\`
|
|
505
523
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
4. Navigate to overview mode:
|
|
524
|
+
For responsive follow-ups, call \`open-visual-edit\` again with the same
|
|
525
|
+
\`designId\` and \`connectionId\`, plus explicit viewport dimensions:
|
|
510
526
|
|
|
511
527
|
\`\`\`bash
|
|
512
|
-
pnpm action
|
|
528
|
+
pnpm action open-visual-edit '{
|
|
529
|
+
"designId": "<existing-design-id>",
|
|
530
|
+
"connectionId": "<existing-connection-id>",
|
|
531
|
+
"devServerUrl": "http://localhost:5173",
|
|
532
|
+
"paths": ["/"],
|
|
533
|
+
"defaultWidth": 390,
|
|
534
|
+
"defaultHeight": 844,
|
|
535
|
+
"startX": 1600,
|
|
536
|
+
"startY": 0
|
|
537
|
+
}'
|
|
513
538
|
\`\`\`
|
|
514
539
|
|
|
540
|
+
If no \`routes\` or \`paths\` are supplied, \`open-visual-edit\` uses every route
|
|
541
|
+
from the localhost manifest.
|
|
542
|
+
|
|
543
|
+
Fallback, only when \`open-visual-edit\` is unavailable:
|
|
544
|
+
|
|
545
|
+
1. Register or refresh the bridge with \`connect-localhost\`, passing the
|
|
546
|
+
\`/manifest.json\` result as \`routeManifest\` and \`capabilities\`.
|
|
547
|
+
2. Create or reuse a Design project with \`create-design\`.
|
|
548
|
+
3. Place URL-backed screens with \`add-localhost-screens\`.
|
|
549
|
+
4. Navigate to overview mode with \`navigate\`.
|
|
550
|
+
|
|
515
551
|
## Open The Design Surface
|
|
516
552
|
|
|
517
553
|
- Use the \`link\`, \`deepLink\`, or MCP App embed returned by Design actions so
|
|
518
554
|
the user sees the canvas. In Codex Desktop or VS Code, prefer opening that
|
|
519
555
|
Design URL in the available preview/webview panel; otherwise surface the
|
|
520
556
|
"Open design" link.
|
|
557
|
+
- Return or open the \`openUrl\` / action link, not a hand-built
|
|
558
|
+
\`/design/:id?_session=...\` URL.
|
|
521
559
|
- If the user is working in VS Code, the Agent Native extension can open the
|
|
522
560
|
same URL via
|
|
523
561
|
\`vscode://builder.agent-native/open?url=<encoded-design-url>\`. Its
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
type WorkspaceAppAudience,
|
|
18
18
|
} from "../shared/workspace-app-audience.js";
|
|
19
19
|
import {
|
|
20
|
+
attachGatewaySocketErrorSink,
|
|
20
21
|
normalizeOrigin,
|
|
21
22
|
rewriteRedirectLocation,
|
|
22
23
|
escapeHtml,
|
|
@@ -1048,9 +1049,18 @@ export async function runWorkspaceDev(
|
|
|
1048
1049
|
if (rewritten) responseHeaders.location = rewritten;
|
|
1049
1050
|
}
|
|
1050
1051
|
res.writeHead(statusCode, responseHeaders);
|
|
1052
|
+
proxyRes.once("error", () => {
|
|
1053
|
+
if (!res.destroyed) res.destroy();
|
|
1054
|
+
});
|
|
1051
1055
|
proxyRes.pipe(res);
|
|
1052
1056
|
},
|
|
1053
1057
|
);
|
|
1058
|
+
proxyReq.once("socket", (socket) => {
|
|
1059
|
+
attachGatewaySocketErrorSink(socket);
|
|
1060
|
+
});
|
|
1061
|
+
res.once("error", () => {
|
|
1062
|
+
proxyReq.destroy();
|
|
1063
|
+
});
|
|
1054
1064
|
responseTimer = setTimeout(() => {
|
|
1055
1065
|
if (settled) return;
|
|
1056
1066
|
settled = true;
|
|
@@ -1123,6 +1133,13 @@ export async function runWorkspaceDev(
|
|
|
1123
1133
|
head: Buffer,
|
|
1124
1134
|
): void {
|
|
1125
1135
|
startApp(app);
|
|
1136
|
+
let target: net.Socket | undefined;
|
|
1137
|
+
attachGatewaySocketErrorSink(socket, () => {
|
|
1138
|
+
target?.destroy();
|
|
1139
|
+
});
|
|
1140
|
+
socket.once("close", () => {
|
|
1141
|
+
target?.destroy();
|
|
1142
|
+
});
|
|
1126
1143
|
void waitForPort(app.port, Date.now() + proxyReadyTimeoutMs).then(
|
|
1127
1144
|
(ready) => {
|
|
1128
1145
|
if (!ready) {
|
|
@@ -1130,8 +1147,9 @@ export async function runWorkspaceDev(
|
|
|
1130
1147
|
socket.destroy();
|
|
1131
1148
|
return;
|
|
1132
1149
|
}
|
|
1150
|
+
if (socket.destroyed) return;
|
|
1133
1151
|
app.ready = true;
|
|
1134
|
-
const
|
|
1152
|
+
const upstream = net.connect(app.port, "127.0.0.1", () => {
|
|
1135
1153
|
const headers = Object.entries(
|
|
1136
1154
|
proxyHeaders(req, `127.0.0.1:${app.port}`),
|
|
1137
1155
|
)
|
|
@@ -1141,14 +1159,20 @@ export async function runWorkspaceDev(
|
|
|
1141
1159
|
: [`${key}: ${value ?? ""}`],
|
|
1142
1160
|
)
|
|
1143
1161
|
.join("\r\n");
|
|
1144
|
-
|
|
1162
|
+
upstream.write(
|
|
1145
1163
|
`${req.method} ${req.url} HTTP/${req.httpVersion}\r\n${headers}\r\n\r\n`,
|
|
1146
1164
|
);
|
|
1147
|
-
if (head.length)
|
|
1148
|
-
socket.pipe(
|
|
1165
|
+
if (head.length) upstream.write(head);
|
|
1166
|
+
socket.pipe(upstream).pipe(socket);
|
|
1149
1167
|
});
|
|
1168
|
+
target = upstream;
|
|
1150
1169
|
|
|
1151
|
-
|
|
1170
|
+
attachGatewaySocketErrorSink(upstream, () => {
|
|
1171
|
+
if (!socket.destroyed) socket.destroy();
|
|
1172
|
+
});
|
|
1173
|
+
upstream.once("close", () => {
|
|
1174
|
+
if (!socket.destroyed) socket.destroy();
|
|
1175
|
+
});
|
|
1152
1176
|
},
|
|
1153
1177
|
);
|
|
1154
1178
|
}
|