@agent-native/core 0.80.11 → 0.81.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/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +47 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/cli/design-connect.ts +419 -19
- package/corpus/core/src/client/ConnectBuilderCard.tsx +1 -0
- package/corpus/core/src/client/chat/index.ts +1 -0
- package/corpus/core/src/client/chat/run-recovery.tsx +9 -7
- package/corpus/core/src/client/chat-view-transition.ts +33 -2
- package/corpus/core/src/client/composer/PromptComposer.tsx +21 -2
- package/corpus/core/src/client/index.ts +1 -0
- package/corpus/core/src/client/org/OrgSwitcher.tsx +26 -4
- package/corpus/core/src/client/sharing/ShareButton.tsx +3 -3
- package/corpus/core/src/client/use-agent-chat-home-handoff.ts +31 -3
- package/corpus/core/src/db/client.ts +29 -2
- package/corpus/core/src/provider-api/index.ts +29 -0
- package/corpus/core/src/server/core-routes-plugin.ts +58 -20
- package/corpus/core/src/styles/agent-native.css +54 -0
- package/corpus/core/src/usage/store.ts +2 -2
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +118 -10
- package/corpus/templates/analytics/app/components/layout/layout-route-policy.ts +7 -0
- package/corpus/templates/analytics/app/global.css +8 -0
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +7 -1
- package/corpus/templates/analytics/app/lib/chat-handoff.ts +34 -0
- package/corpus/templates/analytics/app/pages/Ask.tsx +9 -18
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +2 -2
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +109 -21
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +4 -6
- package/corpus/templates/analytics/changelog/2026-06-30-ask-opens-a-fresh-chat-unless-you-were-just-chatting-and-das.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-30-dashboard-email-reports-are-more-reliable-and-use-cleaner.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-30-dashboard-toolbar-controls-use-a-quieter-share-button-and-ve.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-30-session-replay-rows-show-whole-minute-durations-in-the-playl.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-30-session-replays-now-render-captured-styling-and-keep-the-eve.md +6 -0
- package/corpus/templates/analytics/server/jobs/dashboard-report.ts +16 -3
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +31 -14
- package/corpus/templates/assets/actions/open-asset-picker.ts +9 -0
- package/corpus/templates/assets/app/global.css +15 -0
- package/corpus/templates/assets/app/hooks/use-navigation-state.ts +4 -0
- package/corpus/templates/assets/app/routes/library.tsx +90 -16
- package/corpus/templates/assets/changelog/2026-06-30-the-assets-picker-now-supports-a-vertical-embedded-layout-fo.md +6 -0
- package/corpus/templates/clips/actions/finalize-recording.ts +1 -12
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +10 -5
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +6 -8
- package/corpus/templates/clips/changelog/2026-06-30-extension-save-recovery-avoids-false-upload-failures.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-30-longer-chrome-extension-recordings-now-keep-saving-reliably-.md +6 -0
- package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -1
- package/corpus/templates/clips/chrome-extension/src/background.ts +19 -10
- package/corpus/templates/clips/chrome-extension/src/content-script.ts +38 -12
- package/corpus/templates/clips/chrome-extension/src/finalize-recovery.ts +224 -0
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +119 -16
- package/corpus/templates/clips/chrome-extension/src/overlay.ts +16 -0
- package/corpus/templates/clips/server/lib/recording-upload-state.ts +48 -0
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +9 -1
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +63 -13
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/status.get.ts +74 -0
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +32 -0
- package/corpus/templates/design/AGENTS.md +27 -0
- package/corpus/templates/design/CODE_NATIVE_DESIGN_STUDIO_IMPLEMENTATION_PLAN.md +1 -1
- package/corpus/templates/design/DESIGN-STUDIO-PLAN.md +5 -5
- package/corpus/templates/design/actions/apply-component-prop-edit.ts +63 -20
- package/corpus/templates/design/actions/apply-motion-edit.ts +67 -69
- package/corpus/templates/design/actions/apply-shader-fill.ts +148 -56
- package/corpus/templates/design/actions/capture-design-state.ts +27 -4
- package/corpus/templates/design/actions/connect-localhost.ts +59 -22
- package/corpus/templates/design/actions/export-zip.ts +23 -8
- package/corpus/templates/design/actions/generate-design.ts +53 -1
- package/corpus/templates/design/actions/get-component-details.ts +5 -19
- package/corpus/templates/design/actions/get-motion-timeline.ts +135 -10
- package/corpus/templates/design/actions/grant-localhost-write-consent.ts +116 -0
- package/corpus/templates/design/actions/import-design-tokens.ts +521 -0
- package/corpus/templates/design/actions/index-design-tokens.ts +10 -1
- package/corpus/templates/design/actions/insert-design-native-asset.ts +268 -0
- package/corpus/templates/design/actions/insert-figma-library-asset.ts +233 -0
- package/corpus/templates/design/actions/list-design-extensions.ts +32 -10
- package/corpus/templates/design/actions/list-design-native-assets.ts +105 -0
- package/corpus/templates/design/actions/list-figma-library-assets.ts +292 -0
- package/corpus/templates/design/actions/migrate-board-objects-to-file.ts +238 -0
- package/corpus/templates/design/actions/navigate.ts +18 -3
- package/corpus/templates/design/actions/provider-api-catalog.ts +2 -2
- package/corpus/templates/design/actions/provider-api-docs.ts +1 -1
- package/corpus/templates/design/actions/provider-api-request.ts +3 -3
- package/corpus/templates/design/actions/revoke-localhost-write-consent.ts +48 -0
- package/corpus/templates/design/actions/run-design-audit.ts +53 -4
- package/corpus/templates/design/actions/run-design-extension-action.ts +1 -1
- package/corpus/templates/design/actions/view-screen.ts +1 -1
- package/corpus/templates/design/actions/write-local-file.ts +213 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +230 -3308
- package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +30 -20
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +776 -287
- package/corpus/templates/design/app/components/design/EditPanel.tsx +212 -208
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +14 -2
- package/corpus/templates/design/app/components/design/LocalhostWriteConsentDialog.tsx +161 -0
- package/corpus/templates/design/app/components/design/MotionDock.tsx +235 -266
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +490 -55
- package/corpus/templates/design/app/components/design/ReviewPanel.tsx +43 -62
- package/corpus/templates/design/app/components/design/StatesPanel.tsx +34 -61
- package/corpus/templates/design/app/components/design/TokensPanel.tsx +251 -0
- package/corpus/templates/design/app/components/design/bridge/codegen.ts +125 -0
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +4037 -0
- package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +62 -0
- package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +272 -0
- package/corpus/templates/design/app/components/design/bridge/nav.bridge.ts +116 -0
- package/corpus/templates/design/app/components/design/bridge/sample.bridge.ts +24 -0
- package/corpus/templates/design/app/components/design/bridge/shader-fill-preview.bridge.ts +78 -0
- package/corpus/templates/design/app/components/design/bridge/tsconfig.json +17 -0
- package/corpus/templates/design/app/components/design/bridge/tweak.bridge.ts +28 -0
- package/corpus/templates/design/app/components/design/bridge/zoom.bridge.ts +43 -0
- package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +45 -16
- package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +88 -9
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +94 -9
- package/corpus/templates/design/app/components/layout/Layout.tsx +19 -3
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +1 -1
- package/corpus/templates/design/app/global.css +7 -0
- package/corpus/templates/design/app/hooks/use-navigation-state.ts +23 -0
- package/corpus/templates/design/app/i18n/zh-TW.ts +21 -0
- package/corpus/templates/design/app/i18n-data.ts +358 -0
- package/corpus/templates/design/app/lib/pending-generation.ts +1 -0
- package/corpus/templates/design/app/pages/DesignEditor.tsx +2402 -499
- package/corpus/templates/design/app/pages/Index.tsx +5 -1
- package/corpus/templates/design/changelog/2026-06-30-applying-the-one-click-fix-for-a-small-tap-target-accessibil.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-canvas-creation-screen-dragging-undo-redo-and-image-fill-edi.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-component-prop-edits-and-shader-fills-now-preserve-rapid-sam.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-can-browse-figma-library-components-and-insert-them-i.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-now-has-a-figma-style-left-rail-for-file-agent-assets.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-now-has-native-components-embedded-media-and-figma-im.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-preview-now-includes-a-publish-app-waitlist-option-fr.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-s-left-rail-now-matches-the-sidebar-chrome-and-uses-t.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-s-tools-create-menu-now-stays-compact-instead-of-rend.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-starter-prompts-now-begin-generating-immediately-and-.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-tools-now-use-a-quieter-figma-style-list-layout.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-drawing-rectangles-on-the-all-screens-canvas-no-longer-flash.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-fixed-code-native-design-studio-edits-so-component-props-mot.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-fixed-visual-editing-hover-overlays-and-spacing-handles-so-s.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-motion-edits-now-save-automatically-without-a-separate-css-a.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-motion-timelines-now-reopen-as-editable-tracks-after-writing.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-new-design-prompts-with-uploaded-screenshots-work-reliably-o.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-screen-previews-in-all-screens-view-now-keep-rounded-outline.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-selection-outlines-now-sit-flush-on-rectangles-drawn-directl.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-share-options-use-a-tighter-design-editor-popover-with-compa.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-collapsed-motion-panel-now-stays-tucked-under-the-left-s.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-design-inspector-now-shows-states-and-review-in-a-tighte.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-sidebar-keeps-the-organization-picker-space-stable-while.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-tokens-can-now-be-imported-from-pasted-notes-code-files-fold.md +6 -0
- package/corpus/templates/design/e2e/helpers.ts +168 -65
- package/corpus/templates/design/package.json +3 -1
- package/corpus/templates/design/server/db/schema.ts +23 -0
- package/corpus/templates/design/server/handlers/uploads.ts +22 -1
- package/corpus/templates/design/server/lib/provider-api.ts +7 -4
- package/corpus/templates/design/server/lib/verify-write-grant.ts +108 -0
- package/corpus/templates/design/server/plugins/db.ts +39 -0
- package/corpus/templates/design/server/register-secrets.ts +38 -0
- package/corpus/templates/design/shared/board-file.ts +228 -0
- package/corpus/templates/design/shared/board-objects.ts +288 -0
- package/corpus/templates/design/shared/code-layer.ts +52 -0
- package/corpus/templates/design/shared/motion-compiler.ts +58 -7
- package/corpus/templates/design/shared/motion-timeline.ts +2 -2
- package/corpus/templates/design/tsconfig.json +2 -1
- package/corpus/templates/slides/AGENTS.md +9 -0
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +4 -0
- package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +4 -24
- package/corpus/templates/slides/app/lib/export-pdf-client.ts +29 -20
- package/corpus/templates/slides/app/lib/export-pptx-client.ts +365 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +12 -9
- package/corpus/templates/slides/app/vite-env.d.ts +18 -0
- package/corpus/templates/slides/changelog/2026-06-30-powerpoint-downloads-now-preserve-the-rendered-slide-layout-.md +6 -0
- package/corpus/templates/slides/changelog/2026-06-30-unavailable-decks-open-in-a-cleaner-full-height-centered-sta.md +6 -0
- package/corpus/templates/slides/package.json +1 -0
- package/corpus/templates/slides/vite.config.ts +1 -0
- package/dist/cli/design-connect.d.ts +25 -0
- package/dist/cli/design-connect.d.ts.map +1 -1
- package/dist/cli/design-connect.js +357 -18
- package/dist/cli/design-connect.js.map +1 -1
- package/dist/client/ConnectBuilderCard.d.ts.map +1 -1
- package/dist/client/ConnectBuilderCard.js +1 -0
- package/dist/client/ConnectBuilderCard.js.map +1 -1
- package/dist/client/chat/index.d.ts +1 -1
- package/dist/client/chat/index.d.ts.map +1 -1
- package/dist/client/chat/index.js +1 -1
- package/dist/client/chat/index.js.map +1 -1
- package/dist/client/chat/run-recovery.d.ts.map +1 -1
- package/dist/client/chat/run-recovery.js +5 -5
- package/dist/client/chat/run-recovery.js.map +1 -1
- package/dist/client/chat-view-transition.d.ts +6 -0
- package/dist/client/chat-view-transition.d.ts.map +1 -1
- package/dist/client/chat-view-transition.js +23 -2
- package/dist/client/chat-view-transition.js.map +1 -1
- package/dist/client/composer/PromptComposer.d.ts.map +1 -1
- package/dist/client/composer/PromptComposer.js +3 -2
- package/dist/client/composer/PromptComposer.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
- package/dist/client/org/OrgSwitcher.js +11 -4
- package/dist/client/org/OrgSwitcher.js.map +1 -1
- package/dist/client/sharing/ShareButton.js +3 -3
- package/dist/client/sharing/ShareButton.js.map +1 -1
- package/dist/client/use-agent-chat-home-handoff.d.ts +8 -2
- package/dist/client/use-agent-chat-home-handoff.d.ts.map +1 -1
- package/dist/client/use-agent-chat-home-handoff.js +20 -6
- package/dist/client/use-agent-chat-home-handoff.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +2 -2
- package/dist/db/client.d.ts +1 -0
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +28 -2
- package/dist/db/client.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +2 -2
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/index.d.ts +5 -4
- package/dist/provider-api/index.d.ts.map +1 -1
- package/dist/provider-api/index.js +28 -0
- package/dist/provider-api/index.js.map +1 -1
- package/dist/resources/handlers.d.ts +3 -3
- 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 +43 -18
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/styles/agent-native.css +54 -0
- package/dist/usage/store.js +2 -2
- package/dist/usage/store.js.map +1 -1
- package/package.json +1 -1
|
@@ -132,6 +132,31 @@ export function markAgentChatHomeHandoff(storageKey?: string | null): void {
|
|
|
132
132
|
} catch {}
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Check whether a full-page-chat handoff marker is still recent without
|
|
137
|
+
* consuming it. Use this when a chat route should only restore or animate a
|
|
138
|
+
* conversation if the user actually chatted a moment ago.
|
|
139
|
+
*/
|
|
140
|
+
export function isAgentChatHomeHandoffActive(
|
|
141
|
+
storageKey?: string | null,
|
|
142
|
+
options: AgentChatHomeHandoffOptions = {},
|
|
143
|
+
): boolean {
|
|
144
|
+
if (typeof window === "undefined") return false;
|
|
145
|
+
|
|
146
|
+
let startedAt = 0;
|
|
147
|
+
try {
|
|
148
|
+
const raw = window.sessionStorage.getItem(
|
|
149
|
+
agentChatHomeHandoffKey(storageKey),
|
|
150
|
+
);
|
|
151
|
+
startedAt = raw ? Number.parseInt(raw, 10) : 0;
|
|
152
|
+
} catch {
|
|
153
|
+
startedAt = 0;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const ttlMs = options.ttlMs ?? AGENT_CHAT_HOME_HANDOFF_TTL_MS;
|
|
157
|
+
return Number.isFinite(startedAt) && Date.now() - startedAt <= ttlMs;
|
|
158
|
+
}
|
|
159
|
+
|
|
135
160
|
/**
|
|
136
161
|
* Consume a recent full-page-chat handoff marker. Returns true only once per
|
|
137
162
|
* marker, so layouts can keep `openOnChatRunning` scoped to the route that
|
|
@@ -153,9 +178,15 @@ export function consumeAgentChatHomeHandoff(
|
|
|
153
178
|
startedAt = 0;
|
|
154
179
|
}
|
|
155
180
|
|
|
181
|
+
return isAgentChatHomeHandoffActiveFromTimestamp(startedAt, options);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function isAgentChatHomeHandoffActiveFromTimestamp(
|
|
185
|
+
startedAt: number,
|
|
186
|
+
options: AgentChatHomeHandoffOptions,
|
|
187
|
+
): boolean {
|
|
156
188
|
const ttlMs = options.ttlMs ?? AGENT_CHAT_HOME_HANDOFF_TTL_MS;
|
|
157
|
-
|
|
158
|
-
return active;
|
|
189
|
+
return Number.isFinite(startedAt) && Date.now() - startedAt <= ttlMs;
|
|
159
190
|
}
|
|
160
191
|
|
|
161
192
|
/**
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
|
|
31
31
|
import type { ReasoningEffort } from "../../shared/reasoning-effort.js";
|
|
32
32
|
import { AssistantUiStaleIndexErrorBoundary } from "../assistant-ui-recovery.js";
|
|
33
|
-
import { BuilderSetupCard } from "../chat/run-recovery.js";
|
|
33
|
+
import { BuilderConnectCta, BuilderSetupCard } from "../chat/run-recovery.js";
|
|
34
34
|
import { TooltipProvider } from "../components/ui/tooltip.js";
|
|
35
35
|
import {
|
|
36
36
|
fetchAgentEngineConfiguredState,
|
|
@@ -578,10 +578,11 @@ function PromptComposerInner({
|
|
|
578
578
|
},
|
|
579
579
|
[composerEffort, composerEngine, composerModel, onSubmit],
|
|
580
580
|
);
|
|
581
|
+
const useInlineMissingKeySetup = layoutVariant === "compact";
|
|
581
582
|
|
|
582
583
|
return (
|
|
583
584
|
<>
|
|
584
|
-
{missingApiKey ? (
|
|
585
|
+
{missingApiKey && !useInlineMissingKeySetup ? (
|
|
585
586
|
<BuilderSetupCard
|
|
586
587
|
onConnected={handleBuilderConnected}
|
|
587
588
|
bouncePulse={missingKeyBouncePulse}
|
|
@@ -589,6 +590,24 @@ function PromptComposerInner({
|
|
|
589
590
|
layout="sidebar"
|
|
590
591
|
/>
|
|
591
592
|
) : null}
|
|
593
|
+
{missingApiKey && useInlineMissingKeySetup ? (
|
|
594
|
+
<div className="mb-2 rounded-md border border-border/80 bg-background/80 p-2.5 text-start shadow-sm">
|
|
595
|
+
<div className="flex flex-col gap-2">
|
|
596
|
+
<div className="min-w-0">
|
|
597
|
+
<p className="text-[12px] font-medium text-foreground">
|
|
598
|
+
Connect AI
|
|
599
|
+
</p>
|
|
600
|
+
<p className="mt-0.5 text-[11px] leading-4 text-muted-foreground">
|
|
601
|
+
Connect Builder.io before sending.
|
|
602
|
+
</p>
|
|
603
|
+
</div>
|
|
604
|
+
<BuilderConnectCta
|
|
605
|
+
variant="compact"
|
|
606
|
+
onConnected={handleBuilderConnected}
|
|
607
|
+
/>
|
|
608
|
+
</div>
|
|
609
|
+
</div>
|
|
610
|
+
) : null}
|
|
592
611
|
<AgentComposerFrame
|
|
593
612
|
className={cn(
|
|
594
613
|
"text-start",
|
|
@@ -529,6 +529,7 @@ export {
|
|
|
529
529
|
AGENT_CHAT_VIEW_TRANSITION_NAME,
|
|
530
530
|
consumeAgentChatHomeHandoff,
|
|
531
531
|
getAgentChatViewTransitionStyle,
|
|
532
|
+
isAgentChatHomeHandoffActive,
|
|
532
533
|
markAgentChatHomeHandoff,
|
|
533
534
|
navigateWithAgentChatViewTransition,
|
|
534
535
|
startAgentChatViewTransition,
|
|
@@ -97,6 +97,9 @@ const SECTION_LABEL_CLASS =
|
|
|
97
97
|
const APP_SUBMENU_CONTENT_CLASS =
|
|
98
98
|
"z-50 w-72 rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2";
|
|
99
99
|
|
|
100
|
+
const SWITCHER_BUTTON_CLASS =
|
|
101
|
+
"flex w-full items-center gap-2 rounded-md border border-border/70 px-2.5 py-1.5 text-xs font-medium text-muted-foreground hover:bg-accent/50 hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-60 cursor-pointer";
|
|
102
|
+
|
|
100
103
|
const DEFAULT_ORGANIZATION_SETTINGS_PATH = "/settings#team";
|
|
101
104
|
|
|
102
105
|
const APP_ICON_MAP: Record<string, typeof IconApps> = {
|
|
@@ -274,6 +277,25 @@ function AppsSubmenu({
|
|
|
274
277
|
);
|
|
275
278
|
}
|
|
276
279
|
|
|
280
|
+
function ReservedOrgSwitcherSpace({ className }: { className?: string }) {
|
|
281
|
+
return <div aria-hidden="true" className={`h-8 ${className ?? ""}`} />;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function OrgSwitcherLoadingPlaceholder({ className }: { className?: string }) {
|
|
285
|
+
return (
|
|
286
|
+
<button
|
|
287
|
+
type="button"
|
|
288
|
+
disabled
|
|
289
|
+
aria-label="Loading organization"
|
|
290
|
+
className={`${SWITCHER_BUTTON_CLASS} animate-pulse ${className ?? ""}`}
|
|
291
|
+
>
|
|
292
|
+
<IconBuilding className="h-3.5 w-3.5 shrink-0 opacity-60" />
|
|
293
|
+
<span className="h-3 min-w-0 flex-1 rounded-sm bg-muted-foreground/20" />
|
|
294
|
+
<IconSelector className="h-3 w-3 shrink-0 opacity-30" />
|
|
295
|
+
</button>
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
|
|
277
299
|
/**
|
|
278
300
|
* Compact org switcher button. Shows the active org (or "Personal" when the
|
|
279
301
|
* user has none); opens a popover with the user's other orgs, pending
|
|
@@ -326,7 +348,7 @@ export function OrgSwitcher({
|
|
|
326
348
|
|
|
327
349
|
if (!org) {
|
|
328
350
|
return reserveSpace && isLoading ? (
|
|
329
|
-
<
|
|
351
|
+
<OrgSwitcherLoadingPlaceholder className={className} />
|
|
330
352
|
) : null;
|
|
331
353
|
}
|
|
332
354
|
|
|
@@ -338,7 +360,7 @@ export function OrgSwitcher({
|
|
|
338
360
|
orgCount > 0 || pendingInvitations.length > 0 || domainMatches.length > 0;
|
|
339
361
|
if (!hasAny && !org.email) {
|
|
340
362
|
return reserveSpace ? (
|
|
341
|
-
<
|
|
363
|
+
<ReservedOrgSwitcherSpace className={className} />
|
|
342
364
|
) : null;
|
|
343
365
|
}
|
|
344
366
|
if (
|
|
@@ -348,7 +370,7 @@ export function OrgSwitcher({
|
|
|
348
370
|
domainMatches.length === 0
|
|
349
371
|
) {
|
|
350
372
|
return reserveSpace ? (
|
|
351
|
-
<
|
|
373
|
+
<ReservedOrgSwitcherSpace className={className} />
|
|
352
374
|
) : null;
|
|
353
375
|
}
|
|
354
376
|
|
|
@@ -368,7 +390,7 @@ export function OrgSwitcher({
|
|
|
368
390
|
<PopoverPrimitive.Trigger asChild>
|
|
369
391
|
<button
|
|
370
392
|
type="button"
|
|
371
|
-
className={
|
|
393
|
+
className={`${SWITCHER_BUTTON_CLASS} ${className ?? ""}`}
|
|
372
394
|
>
|
|
373
395
|
<ButtonIcon className="h-3.5 w-3.5 shrink-0" />
|
|
374
396
|
<span className="truncate flex-1 text-start">{buttonLabel}</span>
|
|
@@ -153,13 +153,13 @@ interface SharesResponse {
|
|
|
153
153
|
policy?: SharesPolicy;
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
-
//
|
|
157
|
-
//
|
|
156
|
+
// Match shadcn's <Button size="sm" variant="outline"> sizing so the trigger
|
|
157
|
+
// sits flush next to other controls while staying transparent at rest.
|
|
158
158
|
const BUTTON_BASE =
|
|
159
159
|
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0";
|
|
160
160
|
const BUTTON_OUTLINE_SM = cn(
|
|
161
161
|
BUTTON_BASE,
|
|
162
|
-
"h-9 px-3 border border-[hsl(var(--sidebar-border,var(--input)))] bg-
|
|
162
|
+
"h-9 px-3 border border-[hsl(var(--sidebar-border,var(--input)))] bg-transparent text-foreground hover:bg-[hsl(var(--sidebar-accent,var(--accent)))] hover:text-[hsl(var(--sidebar-accent-foreground,var(--accent-foreground)))]",
|
|
163
163
|
);
|
|
164
164
|
const BUTTON_PRIMARY_SM = cn(
|
|
165
165
|
BUTTON_BASE,
|
|
@@ -4,6 +4,7 @@ import { useLocation, useNavigate } from "react-router";
|
|
|
4
4
|
import { appBasePath } from "./api-path.js";
|
|
5
5
|
import {
|
|
6
6
|
consumeAgentChatHomeHandoff,
|
|
7
|
+
isAgentChatHomeHandoffActive,
|
|
7
8
|
markAgentChatHomeHandoff,
|
|
8
9
|
navigateWithAgentChatViewTransition,
|
|
9
10
|
} from "./chat-view-transition.js";
|
|
@@ -13,6 +14,8 @@ export interface UseAgentChatHomeHandoffOptions {
|
|
|
13
14
|
storageKey?: string | null;
|
|
14
15
|
/** The current destination path that receives the sidebar handoff. */
|
|
15
16
|
activePath: string;
|
|
17
|
+
/** How long the handoff marker remains valid. Defaults to 6 hours. */
|
|
18
|
+
ttlMs?: number;
|
|
16
19
|
/** Disable consumption without changing hook call order. */
|
|
17
20
|
enabled?: boolean;
|
|
18
21
|
}
|
|
@@ -30,6 +33,10 @@ export interface UseAgentChatHomeHandoffLinksOptions {
|
|
|
30
33
|
isChatPath?: (pathname: string) => boolean;
|
|
31
34
|
/** Disable link interception without changing hook call order. */
|
|
32
35
|
enabled?: boolean;
|
|
36
|
+
/** How long the handoff marker remains valid. Defaults to 6 hours. */
|
|
37
|
+
ttlMs?: number;
|
|
38
|
+
/** Only intercept links if a recent handoff marker already exists. */
|
|
39
|
+
requireActiveHandoff?: boolean;
|
|
33
40
|
}
|
|
34
41
|
|
|
35
42
|
function stripBasePath(path: string): string {
|
|
@@ -96,6 +103,10 @@ function shouldHandleAnchorClick(
|
|
|
96
103
|
return true;
|
|
97
104
|
}
|
|
98
105
|
|
|
106
|
+
function handoffTtlOptions(ttlMs: number | undefined) {
|
|
107
|
+
return ttlMs === undefined ? undefined : { ttlMs };
|
|
108
|
+
}
|
|
109
|
+
|
|
99
110
|
/**
|
|
100
111
|
* Returns true for the route that has just received a full-page-chat handoff.
|
|
101
112
|
* Pass the result to `AgentSidebar openOnChatRunning`.
|
|
@@ -103,6 +114,7 @@ function shouldHandleAnchorClick(
|
|
|
103
114
|
export function useAgentChatHomeHandoff({
|
|
104
115
|
storageKey,
|
|
105
116
|
activePath,
|
|
117
|
+
ttlMs,
|
|
106
118
|
enabled = true,
|
|
107
119
|
}: UseAgentChatHomeHandoffOptions): boolean {
|
|
108
120
|
const [handoffPath, setHandoffPath] = useState<string | null>(null);
|
|
@@ -112,10 +124,10 @@ export function useAgentChatHomeHandoff({
|
|
|
112
124
|
setHandoffPath(null);
|
|
113
125
|
return;
|
|
114
126
|
}
|
|
115
|
-
if (consumeAgentChatHomeHandoff(storageKey)) {
|
|
127
|
+
if (consumeAgentChatHomeHandoff(storageKey, handoffTtlOptions(ttlMs))) {
|
|
116
128
|
setHandoffPath(activePath);
|
|
117
129
|
}
|
|
118
|
-
}, [activePath, enabled, storageKey]);
|
|
130
|
+
}, [activePath, enabled, storageKey, ttlMs]);
|
|
119
131
|
|
|
120
132
|
return enabled && handoffPath === activePath;
|
|
121
133
|
}
|
|
@@ -129,6 +141,8 @@ export function useAgentChatHomeHandoffLinks({
|
|
|
129
141
|
chatPath = "/",
|
|
130
142
|
isChatPath,
|
|
131
143
|
enabled = true,
|
|
144
|
+
ttlMs,
|
|
145
|
+
requireActiveHandoff = false,
|
|
132
146
|
}: UseAgentChatHomeHandoffLinksOptions): void {
|
|
133
147
|
const location = useLocation();
|
|
134
148
|
const navigate = useNavigate();
|
|
@@ -161,6 +175,13 @@ export function useAgentChatHomeHandoffLinks({
|
|
|
161
175
|
return;
|
|
162
176
|
}
|
|
163
177
|
|
|
178
|
+
if (
|
|
179
|
+
requireActiveHandoff &&
|
|
180
|
+
!isAgentChatHomeHandoffActive(storageKey, handoffTtlOptions(ttlMs))
|
|
181
|
+
) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
164
185
|
event.preventDefault();
|
|
165
186
|
markAgentChatHomeHandoff(storageKey);
|
|
166
187
|
navigateWithAgentChatViewTransition(navigate, path);
|
|
@@ -168,5 +189,12 @@ export function useAgentChatHomeHandoffLinks({
|
|
|
168
189
|
|
|
169
190
|
document.addEventListener("click", handleClick, true);
|
|
170
191
|
return () => document.removeEventListener("click", handleClick, true);
|
|
171
|
-
}, [
|
|
192
|
+
}, [
|
|
193
|
+
enabled,
|
|
194
|
+
location.pathname,
|
|
195
|
+
navigate,
|
|
196
|
+
requireActiveHandoff,
|
|
197
|
+
storageKey,
|
|
198
|
+
ttlMs,
|
|
199
|
+
]);
|
|
172
200
|
}
|
|
@@ -123,6 +123,33 @@ export function pgliteDataDirFromUrl(url: string): string {
|
|
|
123
123
|
return dataDir;
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
export function pgliteRuntimeDataDir(dataDir: string): string {
|
|
127
|
+
if (dataDir === "memory://") return dataDir;
|
|
128
|
+
if (!isServerlessRuntime() || path.isAbsolute(dataDir)) return dataDir;
|
|
129
|
+
|
|
130
|
+
const safeParts = dataDir
|
|
131
|
+
.split(/[\\/]+/)
|
|
132
|
+
.filter((part) => part && part !== "." && part !== "..");
|
|
133
|
+
const safeRelative =
|
|
134
|
+
safeParts.length > 0
|
|
135
|
+
? path.join(...safeParts)
|
|
136
|
+
: path.join("data", "pglite");
|
|
137
|
+
return path.join("/tmp", safeRelative);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async function preparePgliteDataDir(dataDir: string): Promise<string> {
|
|
141
|
+
const runtimeDataDir = pgliteRuntimeDataDir(dataDir);
|
|
142
|
+
if (runtimeDataDir === "memory://") return runtimeDataDir;
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
const fs = await import("fs");
|
|
146
|
+
fs.mkdirSync(runtimeDataDir, { recursive: true });
|
|
147
|
+
} catch {
|
|
148
|
+
// Edge runtimes may not expose fs. PGlite will surface any real open error.
|
|
149
|
+
}
|
|
150
|
+
return runtimeDataDir;
|
|
151
|
+
}
|
|
152
|
+
|
|
126
153
|
async function importOptionalModule(specifier: string): Promise<any> {
|
|
127
154
|
return import(/* @vite-ignore */ specifier);
|
|
128
155
|
}
|
|
@@ -170,7 +197,7 @@ export async function loadPgliteDrizzle(): Promise<{
|
|
|
170
197
|
const _pgliteClients = new Map<string, Promise<any>>();
|
|
171
198
|
|
|
172
199
|
export async function getPgliteClient(url: string): Promise<any> {
|
|
173
|
-
const dataDir = pgliteDataDirFromUrl(url);
|
|
200
|
+
const dataDir = await preparePgliteDataDir(pgliteDataDirFromUrl(url));
|
|
174
201
|
let ready = _pgliteClients.get(dataDir);
|
|
175
202
|
if (!ready) {
|
|
176
203
|
ready = loadPglitePackage().then(({ PGlite }) => PGlite.create(dataDir));
|
|
@@ -190,7 +217,7 @@ export async function closePgliteClients(): Promise<void> {
|
|
|
190
217
|
}
|
|
191
218
|
|
|
192
219
|
export async function closePgliteClient(url: string): Promise<void> {
|
|
193
|
-
const dataDir = pgliteDataDirFromUrl(url);
|
|
220
|
+
const dataDir = pgliteRuntimeDataDir(pgliteDataDirFromUrl(url));
|
|
194
221
|
const ready = _pgliteClients.get(dataDir);
|
|
195
222
|
_pgliteClients.delete(dataDir);
|
|
196
223
|
if (!ready) return;
|
|
@@ -58,6 +58,7 @@ export const PROVIDER_API_IDS = [
|
|
|
58
58
|
"ga4",
|
|
59
59
|
"gcloud",
|
|
60
60
|
"github",
|
|
61
|
+
"figma",
|
|
61
62
|
"gmail",
|
|
62
63
|
"gong",
|
|
63
64
|
"google_calendar",
|
|
@@ -374,6 +375,7 @@ export interface ProviderApiExample {
|
|
|
374
375
|
label: string;
|
|
375
376
|
method: ProviderApiMethod;
|
|
376
377
|
path: string;
|
|
378
|
+
query?: unknown;
|
|
377
379
|
body?: unknown;
|
|
378
380
|
}
|
|
379
381
|
|
|
@@ -777,6 +779,33 @@ const PROVIDER_CONFIGS: Record<ProviderApiId, ProviderApiConfig> = {
|
|
|
777
779
|
{ label: "Search issues", method: "GET", path: "/search/issues" },
|
|
778
780
|
],
|
|
779
781
|
},
|
|
782
|
+
figma: {
|
|
783
|
+
id: "figma",
|
|
784
|
+
label: "Figma REST API",
|
|
785
|
+
defaultBaseUrl: "https://api.figma.com/v1",
|
|
786
|
+
auth: {
|
|
787
|
+
type: "api-key-header",
|
|
788
|
+
key: "FIGMA_ACCESS_TOKEN",
|
|
789
|
+
header: "X-Figma-Token",
|
|
790
|
+
},
|
|
791
|
+
credentialKeys: ["FIGMA_ACCESS_TOKEN"],
|
|
792
|
+
docsUrls: ["https://www.figma.com/developers/api"],
|
|
793
|
+
allowedHostSuffixes: ["figma.com"],
|
|
794
|
+
templateUses: ["design"],
|
|
795
|
+
examples: [
|
|
796
|
+
{
|
|
797
|
+
label: "List file components",
|
|
798
|
+
method: "GET",
|
|
799
|
+
path: "/files/{fileKey}/components",
|
|
800
|
+
},
|
|
801
|
+
{
|
|
802
|
+
label: "Render file nodes",
|
|
803
|
+
method: "GET",
|
|
804
|
+
path: "/images/{fileKey}",
|
|
805
|
+
query: { ids: "1:2", format: "svg" },
|
|
806
|
+
},
|
|
807
|
+
],
|
|
808
|
+
},
|
|
780
809
|
gmail: {
|
|
781
810
|
id: "gmail",
|
|
782
811
|
label: "Gmail API",
|
|
@@ -236,6 +236,11 @@ export async function runDbHealthProbe(
|
|
|
236
236
|
const DEFAULT_BUILDER_WAITLIST_FORM_ID = "DYTHuM0jlV";
|
|
237
237
|
const DEFAULT_BUILDER_WAITLIST_FORMS_ORIGIN = "https://forms.agent-native.com";
|
|
238
238
|
const BUILDER_WAITLIST_FORM_SOURCE = "connect_builder_card";
|
|
239
|
+
const BUILDER_WAITLIST_DEFAULT_USE_CASE = "builder_agent_background_coding";
|
|
240
|
+
const BUILDER_WAITLIST_USE_CASES = new Set([
|
|
241
|
+
BUILDER_WAITLIST_DEFAULT_USE_CASE,
|
|
242
|
+
"design_publish_app",
|
|
243
|
+
]);
|
|
239
244
|
const BUILDER_WAITLIST_FORM_TIMEOUT_MS = 8000;
|
|
240
245
|
const BUILDER_WAITLIST_TEXT_LIMIT = 4000;
|
|
241
246
|
|
|
@@ -244,12 +249,13 @@ interface BuilderWaitlistFormTarget {
|
|
|
244
249
|
formsOrigin: string;
|
|
245
250
|
}
|
|
246
251
|
|
|
247
|
-
interface BuilderWaitlistBody {
|
|
252
|
+
export interface BuilderWaitlistBody {
|
|
248
253
|
prompt?: unknown;
|
|
249
254
|
orgName?: unknown;
|
|
250
255
|
appUrl?: unknown;
|
|
251
256
|
pageUrl?: unknown;
|
|
252
257
|
source?: unknown;
|
|
258
|
+
useCase?: unknown;
|
|
253
259
|
}
|
|
254
260
|
|
|
255
261
|
export function resolveFrameworkSseRoutes(sseRoute?: string): string[] {
|
|
@@ -274,6 +280,13 @@ function cleanBuilderWaitlistText(
|
|
|
274
280
|
return trimmed.slice(0, maxLength);
|
|
275
281
|
}
|
|
276
282
|
|
|
283
|
+
function normalizeBuilderWaitlistUseCase(value: unknown): string {
|
|
284
|
+
const useCase = cleanBuilderWaitlistText(value, 100);
|
|
285
|
+
return useCase && BUILDER_WAITLIST_USE_CASES.has(useCase)
|
|
286
|
+
? useCase
|
|
287
|
+
: BUILDER_WAITLIST_DEFAULT_USE_CASE;
|
|
288
|
+
}
|
|
289
|
+
|
|
277
290
|
function normalizeHttpOrigin(value: string): string | null {
|
|
278
291
|
try {
|
|
279
292
|
const url = new URL(value);
|
|
@@ -317,20 +330,45 @@ export function resolveBuilderWaitlistFormTargetForRequest(
|
|
|
317
330
|
return { formId, formsOrigin };
|
|
318
331
|
}
|
|
319
332
|
|
|
320
|
-
|
|
333
|
+
export function buildBuilderWaitlistFormPayload(
|
|
321
334
|
event: H3Event,
|
|
322
335
|
sessionEmail: string,
|
|
323
336
|
body: BuilderWaitlistBody,
|
|
324
|
-
)
|
|
325
|
-
const target = resolveBuilderWaitlistFormTargetForRequest(event);
|
|
326
|
-
if (!target) return { submitted: false };
|
|
327
|
-
|
|
337
|
+
) {
|
|
328
338
|
const appUrl =
|
|
329
339
|
cleanBuilderWaitlistText(body.pageUrl ?? body.appUrl, 2000) ??
|
|
330
340
|
cleanBuilderWaitlistText(getHeader(event, "referer"), 2000) ??
|
|
331
341
|
getOrigin(event);
|
|
332
342
|
const source =
|
|
333
343
|
cleanBuilderWaitlistText(body.source, 100) ?? BUILDER_WAITLIST_FORM_SOURCE;
|
|
344
|
+
const useCase = normalizeBuilderWaitlistUseCase(body.useCase);
|
|
345
|
+
|
|
346
|
+
return {
|
|
347
|
+
data: {
|
|
348
|
+
email: sessionEmail,
|
|
349
|
+
orgName: cleanBuilderWaitlistText(body.orgName, 500),
|
|
350
|
+
appUrl,
|
|
351
|
+
prompt: cleanBuilderWaitlistText(body.prompt),
|
|
352
|
+
source,
|
|
353
|
+
useCase,
|
|
354
|
+
},
|
|
355
|
+
_hp: "",
|
|
356
|
+
_meta: {
|
|
357
|
+
submitterEmail: sessionEmail,
|
|
358
|
+
pageUrl: appUrl,
|
|
359
|
+
source,
|
|
360
|
+
useCase,
|
|
361
|
+
},
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
async function submitBuilderWaitlistForm(
|
|
366
|
+
event: H3Event,
|
|
367
|
+
sessionEmail: string,
|
|
368
|
+
body: BuilderWaitlistBody,
|
|
369
|
+
): Promise<{ submitted: boolean; formId?: string }> {
|
|
370
|
+
const target = resolveBuilderWaitlistFormTargetForRequest(event);
|
|
371
|
+
if (!target) return { submitted: false };
|
|
334
372
|
|
|
335
373
|
const controller = new AbortController();
|
|
336
374
|
const timeout = setTimeout(
|
|
@@ -344,20 +382,9 @@ async function submitBuilderWaitlistForm(
|
|
|
344
382
|
{
|
|
345
383
|
method: "POST",
|
|
346
384
|
headers: { "Content-Type": "application/json" },
|
|
347
|
-
body: JSON.stringify(
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
orgName: cleanBuilderWaitlistText(body.orgName, 500),
|
|
351
|
-
appUrl,
|
|
352
|
-
prompt: cleanBuilderWaitlistText(body.prompt),
|
|
353
|
-
source,
|
|
354
|
-
},
|
|
355
|
-
_hp: "",
|
|
356
|
-
_meta: {
|
|
357
|
-
submitterEmail: sessionEmail,
|
|
358
|
-
pageUrl: appUrl,
|
|
359
|
-
},
|
|
360
|
-
}),
|
|
385
|
+
body: JSON.stringify(
|
|
386
|
+
buildBuilderWaitlistFormPayload(event, sessionEmail, body),
|
|
387
|
+
),
|
|
361
388
|
signal: controller.signal,
|
|
362
389
|
},
|
|
363
390
|
);
|
|
@@ -1671,6 +1698,13 @@ export function createCoreRoutesPlugin(
|
|
|
1671
1698
|
}
|
|
1672
1699
|
const body = ((await readBody(event).catch(() => ({}))) ??
|
|
1673
1700
|
{}) as BuilderWaitlistBody;
|
|
1701
|
+
const waitlistPayload = buildBuilderWaitlistFormPayload(
|
|
1702
|
+
event,
|
|
1703
|
+
session.email,
|
|
1704
|
+
body,
|
|
1705
|
+
);
|
|
1706
|
+
const waitlistSource = waitlistPayload.data.source;
|
|
1707
|
+
const waitlistUseCase = waitlistPayload.data.useCase;
|
|
1674
1708
|
let formSubmission: { submitted: boolean; formId?: string };
|
|
1675
1709
|
try {
|
|
1676
1710
|
formSubmission = await submitBuilderWaitlistForm(
|
|
@@ -1686,7 +1720,9 @@ export function createCoreRoutesPlugin(
|
|
|
1686
1720
|
{
|
|
1687
1721
|
reason:
|
|
1688
1722
|
err instanceof Error ? err.message : "unknown_waitlist_error",
|
|
1723
|
+
source: waitlistSource,
|
|
1689
1724
|
stage: "waitlist",
|
|
1725
|
+
useCase: waitlistUseCase,
|
|
1690
1726
|
},
|
|
1691
1727
|
);
|
|
1692
1728
|
setResponseStatus(event, 502);
|
|
@@ -1702,7 +1738,9 @@ export function createCoreRoutesPlugin(
|
|
|
1702
1738
|
{
|
|
1703
1739
|
formId: formSubmission.formId ?? null,
|
|
1704
1740
|
formSubmitted: formSubmission.submitted,
|
|
1741
|
+
source: waitlistSource,
|
|
1705
1742
|
stage: "waitlist",
|
|
1743
|
+
useCase: waitlistUseCase,
|
|
1706
1744
|
},
|
|
1707
1745
|
);
|
|
1708
1746
|
return { ok: true, formSubmitted: formSubmission.submitted };
|
|
@@ -537,6 +537,60 @@
|
|
|
537
537
|
}
|
|
538
538
|
}
|
|
539
539
|
|
|
540
|
+
/* Connect AI card: use the card width, not the viewport, so narrow embedded
|
|
541
|
+
sidebars stack the copy and actions before the secondary button clips. */
|
|
542
|
+
.agent-builder-setup-card {
|
|
543
|
+
min-inline-size: min(18rem, 100%);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
.agent-builder-setup-card--sidebar {
|
|
547
|
+
container-type: inline-size;
|
|
548
|
+
container-name: agent-builder-setup;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
@container agent-builder-setup (max-width: 560px) {
|
|
552
|
+
.agent-builder-setup-card__content {
|
|
553
|
+
align-items: stretch;
|
|
554
|
+
flex-direction: column;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
.agent-builder-setup-card__actions {
|
|
558
|
+
align-items: center;
|
|
559
|
+
flex-direction: row;
|
|
560
|
+
flex-wrap: wrap;
|
|
561
|
+
gap: 0.5rem;
|
|
562
|
+
width: 100%;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
.agent-builder-setup-card__builder-cta {
|
|
566
|
+
align-items: stretch;
|
|
567
|
+
flex: 1 1 11rem;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
.agent-builder-setup-card__builder-button,
|
|
571
|
+
.agent-builder-setup-card__key-button {
|
|
572
|
+
justify-content: center;
|
|
573
|
+
min-width: 0;
|
|
574
|
+
width: 100%;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
.agent-builder-setup-card__key-button {
|
|
578
|
+
border: 1px solid hsl(var(--border));
|
|
579
|
+
background: hsl(var(--background));
|
|
580
|
+
color: hsl(var(--foreground));
|
|
581
|
+
flex: 1 1 8rem;
|
|
582
|
+
height: 2rem;
|
|
583
|
+
padding-inline: 0.75rem;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
@container agent-builder-setup (max-width: 360px) {
|
|
588
|
+
.agent-builder-setup-card__actions {
|
|
589
|
+
align-items: stretch;
|
|
590
|
+
flex-direction: column;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
540
594
|
.agent-composer-area--hero {
|
|
541
595
|
padding-inline: 0;
|
|
542
596
|
padding-block: 0.5rem;
|
|
@@ -112,12 +112,12 @@ const PRICING: Array<{ match: RegExp; pricing: ModelPricing }> = [
|
|
|
112
112
|
// ── Google Gemini ───────────────────────────────────────────────────────────
|
|
113
113
|
// Gemini 3 Pro / 3.1 Pro: ~$1.25/$10 per MTok (approximate; verify on billing)
|
|
114
114
|
{
|
|
115
|
-
match: /gemini-3[
|
|
115
|
+
match: /gemini-3[.-]1-pro/i,
|
|
116
116
|
pricing: { input: 125, output: 1000, cacheRead: 31, cacheWrite: 0 },
|
|
117
117
|
},
|
|
118
118
|
// Gemini 3.5 Flash / 3 Flash: ~$0.15/$0.60 per MTok
|
|
119
119
|
{
|
|
120
|
-
match: /gemini-3[
|
|
120
|
+
match: /gemini-3[.-][0-9]+-flash/i,
|
|
121
121
|
pricing: { input: 15, output: 60, cacheRead: 4, cacheWrite: 0 },
|
|
122
122
|
},
|
|
123
123
|
// Gemini 2.5 Pro/Flash (catch-all for older 2.5)
|