@agent-native/core 0.137.3 → 0.137.4

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.
Files changed (178) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  3. package/corpus/templates/analytics/.agents/skills/frontend-design/SKILL.md +53 -1
  4. package/corpus/templates/analytics/actions/gong-calls.ts +37 -17
  5. package/corpus/templates/analytics/app/lib/data-sources.ts +1 -1
  6. package/corpus/templates/analytics/server/lib/gong.ts +51 -2
  7. package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  8. package/corpus/templates/assets/.agents/skills/frontend-design/SKILL.md +53 -1
  9. package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  10. package/corpus/templates/brain/.agents/skills/frontend-design/SKILL.md +53 -1
  11. package/corpus/templates/brain/app/routes/settings.tsx +1 -1
  12. package/corpus/templates/brain/server/register-secrets.ts +1 -1
  13. package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  14. package/corpus/templates/calendar/.agents/skills/frontend-design/SKILL.md +53 -1
  15. package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  16. package/corpus/templates/chat/.agents/skills/frontend-design/SKILL.md +53 -1
  17. package/corpus/templates/chat/AGENTS.md +11 -0
  18. package/corpus/templates/chat/app/components/layout/Layout.tsx +1 -1
  19. package/corpus/templates/chat/app/root.tsx +1 -1
  20. package/corpus/templates/chat/app/routes/agent.tsx +29 -13
  21. package/corpus/templates/chat/vite.config.ts +42 -0
  22. package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  23. package/corpus/templates/clips/.agents/skills/frontend-design/SKILL.md +53 -1
  24. package/corpus/templates/clips/app/components/library/empty-state.tsx +1 -3
  25. package/corpus/templates/clips/app/components/library/library-grid.tsx +2 -6
  26. package/corpus/templates/clips/app/components/library/library-layout.tsx +2 -6
  27. package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +1 -3
  28. package/corpus/templates/clips/app/routes/bug-report.tsx +1 -8
  29. package/corpus/templates/clips/app/routes/import.tsx +1 -3
  30. package/corpus/templates/clips/changelog/2026-08-04-recording-buttons-are-now-text-only-for-a-cleaner-clips-inte.md +6 -0
  31. package/corpus/templates/clips/changelog/2026-08-04-save-settings-now-matches-the-other-clips-settings-buttons.md +6 -0
  32. package/corpus/templates/clips/chrome-extension/src/styles.css +1 -0
  33. package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  34. package/corpus/templates/content/.agents/skills/frontend-design/SKILL.md +53 -1
  35. package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  36. package/corpus/templates/crm/app/routes/settings.tsx +2 -2
  37. package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  38. package/corpus/templates/design/.agents/skills/frontend-design/SKILL.md +53 -1
  39. package/corpus/templates/design/actions/import-figma-clipboard.ts +1 -1
  40. package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  41. package/corpus/templates/dispatch/.agents/skills/frontend-design/SKILL.md +53 -1
  42. package/corpus/templates/dispatch/changelog/2026-08-04-dispatch-keeps-connected-chats-out-of-local-history-by-defau.md +6 -0
  43. package/corpus/templates/factory/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  44. package/corpus/templates/factory/.agents/skills/frontend-design/SKILL.md +53 -1
  45. package/corpus/templates/factory/README.md +1 -1
  46. package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  47. package/corpus/templates/forms/.agents/skills/frontend-design/SKILL.md +53 -1
  48. package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  49. package/corpus/templates/macros/.agents/skills/frontend-design/SKILL.md +53 -1
  50. package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  51. package/corpus/templates/mail/.agents/skills/frontend-design/SKILL.md +53 -1
  52. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +0 -2
  53. package/corpus/templates/mail/app/pages/SettingsPage.tsx +1 -1
  54. package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  55. package/corpus/templates/plan/.agents/skills/frontend-design/SKILL.md +53 -1
  56. package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  57. package/corpus/templates/slides/.agents/skills/frontend-design/SKILL.md +53 -1
  58. package/corpus/templates/slides/actions/generate-image-api.ts +15 -4
  59. package/corpus/templates/slides/actions/import-google-slides-reference.ts +83 -0
  60. package/corpus/templates/slides/actions/import-pptx.ts +134 -117
  61. package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +387 -0
  62. package/corpus/templates/slides/app/components/editor/ImageGenPanel.tsx +78 -48
  63. package/corpus/templates/slides/app/components/editor/NewDeckReferenceStep.tsx +377 -187
  64. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +0 -1
  65. package/corpus/templates/slides/app/hooks/use-deck-design-system.ts +20 -1
  66. package/corpus/templates/slides/app/i18n/en-US.ts +15 -0
  67. package/corpus/templates/slides/app/lib/new-deck-reference-selection.ts +22 -0
  68. package/corpus/templates/slides/app/pages/DeckEditor.tsx +4 -1
  69. package/corpus/templates/slides/app/pages/Index.tsx +172 -85
  70. package/corpus/templates/slides/server/lib/assets-image-delegation.ts +4 -2
  71. package/corpus/templates/slides/shared/api.ts +14 -1
  72. package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  73. package/corpus/templates/tasks/.agents/skills/frontend-design/SKILL.md +53 -1
  74. package/dist/chat-threads/schema.d.ts +57 -0
  75. package/dist/chat-threads/schema.js +3 -0
  76. package/dist/chat-threads/store.d.ts +26 -0
  77. package/dist/chat-threads/store.js +84 -6
  78. package/dist/client/AgentPanel.js +11 -5
  79. package/dist/client/ConnectBuilderCard.js +1 -1
  80. package/dist/client/agent-page/AgentEmptyState.d.ts +2 -1
  81. package/dist/client/agent-page/AgentEmptyState.js +6 -2
  82. package/dist/client/agent-page/AgentJobsTab.d.ts +3 -1
  83. package/dist/client/agent-page/AgentJobsTab.js +55 -44
  84. package/dist/client/agent-page/AgentTabFrame.d.ts +2 -1
  85. package/dist/client/agent-page/AgentTabFrame.js +4 -2
  86. package/dist/client/agent-page/AgentTabsPage.js +12 -8
  87. package/dist/client/agent-page/AgentWorkspaceContent.d.ts +10 -0
  88. package/dist/client/agent-page/AgentWorkspaceContent.js +110 -0
  89. package/dist/client/agent-page/AutomationDetailsDialog.js +1 -1
  90. package/dist/client/chat/run-recovery.js +3 -3
  91. package/dist/client/error-format.js +1 -1
  92. package/dist/client/integrations/IntegrationsPanel.d.ts +1 -0
  93. package/dist/client/integrations/IntegrationsPanel.js +149 -5
  94. package/dist/client/onboarding/FirstRunOnboarding.js +130 -15
  95. package/dist/client/onboarding/index.d.ts +1 -1
  96. package/dist/client/onboarding/index.js +1 -1
  97. package/dist/client/onboarding/use-onboarding.js +12 -2
  98. package/dist/client/onboarding/use-preview-mode.d.ts +4 -0
  99. package/dist/client/onboarding/use-preview-mode.js +9 -0
  100. package/dist/client/resources/BuiltinCapabilityDetail.js +2 -2
  101. package/dist/client/resources/ResourceTree.d.ts +4 -1
  102. package/dist/client/resources/ResourceTree.js +13 -8
  103. package/dist/client/resources/ResourcesPanel.js +7 -3
  104. package/dist/client/resources/mcp-integration-catalog.js +4 -4
  105. package/dist/client/resources/use-mcp-servers.js +6 -6
  106. package/dist/client/settings/AgentsSection.js +15 -16
  107. package/dist/client/settings/AutomationsSection.js +1 -1
  108. package/dist/client/settings/DemoModeSection.js +1 -1
  109. package/dist/client/settings/SettingsPanel.d.ts +3 -1
  110. package/dist/client/settings/SettingsPanel.js +284 -88
  111. package/dist/client/settings/SettingsRow.js +1 -1
  112. package/dist/client/settings/SettingsSection.d.ts +6 -4
  113. package/dist/client/settings/SettingsSection.js +6 -6
  114. package/dist/client/settings/SettingsTabsPage.js +47 -25
  115. package/dist/client/settings/VoiceTranscriptionSection.d.ts +3 -1
  116. package/dist/client/settings/VoiceTranscriptionSection.js +20 -8
  117. package/dist/client/settings/agent-settings-search.d.ts +1 -1
  118. package/dist/client/settings/agent-settings-search.js +8 -8
  119. package/dist/client/transcription/BuilderTranscriptionCta.js +2 -2
  120. package/dist/client/use-chat-threads.d.ts +9 -0
  121. package/dist/client/use-chat-threads.js +22 -6
  122. package/dist/collab/awareness.d.ts +2 -2
  123. package/dist/collab/routes.d.ts +1 -1
  124. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  125. package/dist/integrations/google-docs-poller.js +9 -1
  126. package/dist/integrations/webhook-handler.js +11 -1
  127. package/dist/jobs/scheduler.d.ts +4 -1
  128. package/dist/jobs/scheduler.js +34 -9
  129. package/dist/localization/default-messages.js +40 -40
  130. package/dist/mcp-client/oauth-routes.js +1 -1
  131. package/dist/notifications/routes.d.ts +1 -1
  132. package/dist/provider-api/actions/custom-provider-registration.d.ts +14 -14
  133. package/dist/provider-api/actions/provider-api.d.ts +15 -15
  134. package/dist/secrets/onboarding.js +1 -1
  135. package/dist/secrets/routes.d.ts +6 -6
  136. package/dist/server/agent-chat/browser-team-tools.d.ts +1 -0
  137. package/dist/server/agent-chat/browser-team-tools.js +1 -0
  138. package/dist/server/agent-chat-plugin.js +14 -1
  139. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  140. package/dist/server/agent-teams.d.ts +2 -0
  141. package/dist/server/agent-teams.js +2 -0
  142. package/dist/server/realtime-token.d.ts +1 -1
  143. package/dist/server/workspace-provider-oauth.js +1 -1
  144. package/dist/setup-connections/onboarding.js +2 -2
  145. package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  146. package/dist/templates/chat/.agents/skills/frontend-design/SKILL.md +53 -1
  147. package/dist/templates/chat/AGENTS.md +11 -0
  148. package/dist/templates/chat/app/components/layout/Layout.tsx +1 -1
  149. package/dist/templates/chat/app/root.tsx +1 -1
  150. package/dist/templates/chat/app/routes/agent.tsx +29 -13
  151. package/dist/templates/chat/vite.config.ts +42 -0
  152. package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  153. package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +53 -1
  154. package/dist/templates/default/AGENTS.md +11 -0
  155. package/dist/templates/default/vite.config.ts +42 -0
  156. package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  157. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  158. package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +53 -1
  159. package/dist/templates/workspace-core/AGENTS.md +11 -0
  160. package/dist/templates/workspace-root/AGENTS.md +14 -0
  161. package/dist/vite/client.js +56 -0
  162. package/package.json +2 -2
  163. package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  164. package/src/templates/chat/.agents/skills/frontend-design/SKILL.md +53 -1
  165. package/src/templates/chat/AGENTS.md +11 -0
  166. package/src/templates/chat/app/components/layout/Layout.tsx +1 -1
  167. package/src/templates/chat/app/root.tsx +1 -1
  168. package/src/templates/chat/app/routes/agent.tsx +29 -13
  169. package/src/templates/chat/vite.config.ts +42 -0
  170. package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  171. package/src/templates/default/.agents/skills/frontend-design/SKILL.md +53 -1
  172. package/src/templates/default/AGENTS.md +11 -0
  173. package/src/templates/default/vite.config.ts +42 -0
  174. package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  175. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +33 -0
  176. package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +53 -1
  177. package/src/templates/workspace-core/AGENTS.md +11 -0
  178. package/src/templates/workspace-root/AGENTS.md +14 -0
@@ -1,9 +1,12 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { IconPlus, IconBrandSlack, IconBrandTelegram, IconBrandWhatsapp, IconBrandGoogleDrive, IconTerminal2, IconBuildingSkyscraper, IconCopy, IconCheck, IconChevronLeft, IconExternalLink, IconCircleCheck, IconInfoCircle, } from "@tabler/icons-react";
3
- import { useState, useCallback, useEffect } from "react";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { IconPlus, IconBrandSlack, IconBrandTelegram, IconBrandWhatsapp, IconBrandGoogleDrive, IconTerminal2, IconBuildingSkyscraper, IconCopy, IconCheck, IconChevronLeft, IconChevronRight, IconExternalLink, IconCircleCheck, IconInfoCircle, IconSearch, IconServer, } from "@tabler/icons-react";
3
+ import { useState, useCallback, useEffect, useMemo } from "react";
4
4
  import { agentNativePath } from "../api-path.js";
5
5
  import { Tooltip, TooltipContent, TooltipTrigger, } from "../components/ui/tooltip.js";
6
6
  import { useT } from "../i18n.js";
7
+ import { getDefaultMcpIntegrations, } from "../resources/mcp-integration-catalog.js";
8
+ import { McpIntegrationDialog } from "../resources/McpIntegrationDialog.js";
9
+ import { useCreateMcpServer, useDeleteMcpServer, useMcpServers, } from "../resources/use-mcp-servers.js";
7
10
  import { useIntegrationStatus, } from "./useIntegrationStatus.js";
8
11
  import { isNonPublicWebhookUrl } from "./webhook-url.js";
9
12
  const PLATFORMS = [
@@ -21,6 +24,7 @@ const PLATFORMS = [
21
24
  "Running inside a Dispatch workspace instead? Connect Slack from Settings → Messaging there — it stores workspace tokens for you and this page is not needed.",
22
25
  ],
23
26
  docsUrl: "https://api.slack.com/apps",
27
+ category: "Messaging",
24
28
  },
25
29
  {
26
30
  id: "telegram",
@@ -33,6 +37,7 @@ const PLATFORMS = [
33
37
  "Copy the bot token into your environment",
34
38
  'Click "Setup webhook" below to register automatically',
35
39
  ],
40
+ category: "Messaging",
36
41
  },
37
42
  {
38
43
  id: "whatsapp",
@@ -47,6 +52,7 @@ const PLATFORMS = [
47
52
  "Copy the access token into your environment",
48
53
  ],
49
54
  docsUrl: "https://developers.facebook.com/docs/whatsapp",
55
+ category: "Messaging",
50
56
  },
51
57
  {
52
58
  id: "google-docs",
@@ -60,6 +66,7 @@ const PLATFORMS = [
60
66
  "Share your Google Docs with the service account email",
61
67
  'Write a comment containing "@Agent" to trigger the agent',
62
68
  ],
69
+ category: "Workspace tools",
63
70
  },
64
71
  {
65
72
  id: "openclaw",
@@ -73,6 +80,7 @@ const PLATFORMS = [
73
80
  "Add this agent's URL as a provider in your OpenClaw config",
74
81
  "OpenClaw discovers your agent's capabilities via the A2A protocol",
75
82
  ],
83
+ category: "Agent clients",
76
84
  },
77
85
  {
78
86
  id: "claude-code",
@@ -86,6 +94,7 @@ const PLATFORMS = [
86
94
  "In Claude Code, reference your agent's URL when asking for data",
87
95
  "Claude Code will discover and call your agent's skills automatically",
88
96
  ],
97
+ category: "Agent clients",
89
98
  },
90
99
  {
91
100
  id: "builder",
@@ -100,6 +109,7 @@ const PLATFORMS = [
100
109
  "Chat with one agent that can trigger actions across all your apps",
101
110
  ],
102
111
  docsUrl: "https://www.builder.io?utm_source=agent-native&utm_medium=product&utm_campaign=integrations&utm_content=integrations_panel",
112
+ category: "Agent clients",
103
113
  },
104
114
  ];
105
115
  function useAgentEngineConfigured() {
@@ -184,10 +194,10 @@ function IntegrationDetail({ platform, serverStatus, onBack, onRefresh, }) {
184
194
  }
185
195
  // ─── Add integration picker ──────────────────────────────────────────────────
186
196
  function AddIntegrationPicker({ connectedIds, onSelect, }) {
187
- return (_jsx("div", { className: "space-y-1", children: PLATFORMS.filter((p) => !connectedIds.has(p.id)).map((platform) => (_jsxs("button", { onClick: () => onSelect(platform), className: "flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-start hover:bg-accent/50", children: [_jsx(platform.icon, { size: 14, className: "shrink-0 text-muted-foreground" }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("div", { className: "text-[11px] font-medium text-foreground", children: platform.label }), _jsx("div", { className: "text-[10px] text-muted-foreground truncate", children: platform.description })] })] }, platform.id))) }));
197
+ return (_jsx("div", { className: "space-y-1", children: PLATFORMS.filter((platform) => !connectedIds.has(platform.id)).map((platform) => (_jsxs("button", { type: "button", onClick: () => onSelect(platform), className: "flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-start hover:bg-accent/50", children: [_jsx(platform.icon, { size: 14, className: "shrink-0 text-muted-foreground" }), _jsxs("span", { className: "flex-1 min-w-0", children: [_jsx("span", { className: "block text-[11px] font-medium text-foreground", children: platform.label }), _jsx("span", { className: "block truncate text-[10px] text-muted-foreground", children: platform.description })] })] }, platform.id))) }));
188
198
  }
189
199
  // ─── Main panel ──────────────────────────────────────────────────────────────
190
- export function IntegrationsPanel() {
200
+ export function LegacyIntegrationsPanel() {
191
201
  const t = useT();
192
202
  const { statuses, loading, refetch } = useIntegrationStatus();
193
203
  const [selectedPlatform, setSelectedPlatform] = useState(null);
@@ -217,4 +227,138 @@ export function IntegrationsPanel() {
217
227
  : "bg-muted-foreground/55"}` }))] }, platform.id));
218
228
  }), _jsx("div", { className: "rounded-md border border-border bg-muted/30 px-2.5 py-2 text-[10px] text-muted-foreground", children: t("integrations.sharedMessaging") })] }))] }));
219
229
  }
230
+ function IntegrationGalleryCard({ platform, status, onSelect, }) {
231
+ const connected = Boolean(status?.configured || status?.enabled);
232
+ const active = Boolean(status?.enabled && status?.configured);
233
+ const stateLabel = platform.isClient
234
+ ? "Available"
235
+ : active
236
+ ? "Connected"
237
+ : connected
238
+ ? "Ready to enable"
239
+ : "Set up";
240
+ return (_jsxs("button", { type: "button", onClick: () => onSelect(platform), className: "group flex min-h-28 items-start gap-3 rounded-xl border border-border/80 bg-card p-4 text-start transition-colors hover:border-foreground/25 hover:bg-accent/30 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: [_jsx("span", { className: "flex size-10 shrink-0 items-center justify-center rounded-xl border border-border/70 bg-background text-foreground shadow-sm", children: _jsx(platform.icon, { size: 21, strokeWidth: 1.8 }) }), _jsxs("span", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [_jsxs("span", { className: "flex items-center gap-2", children: [_jsx("span", { className: "truncate text-sm font-semibold text-foreground", children: platform.label }), _jsx("span", { className: active
241
+ ? "shrink-0 text-[10px] font-medium text-emerald-600 dark:text-emerald-400"
242
+ : connected
243
+ ? "shrink-0 text-[10px] font-medium text-amber-600 dark:text-amber-400"
244
+ : "shrink-0 text-[10px] text-muted-foreground", children: stateLabel })] }), _jsx("span", { className: "line-clamp-2 text-xs leading-5 text-muted-foreground", children: platform.description }), _jsxs("span", { className: "mt-1 flex items-center gap-1 text-[11px] font-medium text-foreground/70 transition-colors group-hover:text-foreground", children: [connected || platform.isClient ? "Manage" : "Connect", _jsx(IconChevronRight, { className: "size-3.5 rtl:-scale-x-100" })] })] })] }));
245
+ }
246
+ function compareMcpUrl(value) {
247
+ try {
248
+ const url = new URL(value.trim());
249
+ url.hash = "";
250
+ return url.toString().replace(/\/+$/, "");
251
+ }
252
+ catch {
253
+ return value.trim().replace(/\/+$/, "");
254
+ }
255
+ }
256
+ function McpLogo({ integration }) {
257
+ const [failed, setFailed] = useState(false);
258
+ return (_jsx("span", { className: "flex size-9 shrink-0 items-center justify-center overflow-hidden rounded-lg border border-border/70 bg-background text-xs font-semibold text-muted-foreground", children: failed ? (integration.name.slice(0, 1)) : (_jsx("img", { src: integration.logoUrl, alt: "", loading: "lazy", decoding: "async", className: "size-7 object-contain", onError: () => setFailed(true) })) }));
259
+ }
260
+ function McpServerStatus({ server }) {
261
+ if (server.status.state === "connected") {
262
+ return (_jsxs("span", { className: "inline-flex items-center gap-1.5 text-xs text-emerald-600 dark:text-emerald-400", children: [_jsx("span", { className: "size-1.5 rounded-full bg-emerald-500" }), "Connected \u00B7 ", server.status.toolCount, " tool", server.status.toolCount === 1 ? "" : "s"] }));
263
+ }
264
+ if (server.status.state === "error") {
265
+ return (_jsxs("span", { className: "inline-flex items-center gap-1.5 text-xs text-destructive", children: [_jsx("span", { className: "size-1.5 rounded-full bg-destructive" }), "Connection error"] }));
266
+ }
267
+ return (_jsxs("span", { className: "inline-flex items-center gap-1.5 text-xs text-muted-foreground", children: [_jsx("span", { className: "size-1.5 rounded-full bg-muted-foreground/50" }), "Status unknown"] }));
268
+ }
269
+ function McpCatalogItem({ integration, connected, onConnect, }) {
270
+ return (_jsxs("div", { className: "flex min-w-0 items-center gap-3 border-b border-border/60 py-4 last:border-b-0", children: [_jsx(McpLogo, { integration: integration }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "truncate text-sm font-medium text-foreground", children: integration.name }), connected && (_jsx("span", { className: "shrink-0 text-[11px] font-medium text-emerald-600 dark:text-emerald-400", children: "Connected" }))] }), _jsx("p", { className: "mt-0.5 line-clamp-1 text-xs leading-5 text-muted-foreground", children: integration.description || integration.useCase })] }), _jsx("button", { type: "button", onClick: () => onConnect(integration.id), className: "shrink-0 rounded-md border border-border bg-background px-2.5 py-1.5 text-xs font-medium text-foreground transition-colors hover:bg-accent", children: connected ? "Manage" : "Connect" })] }));
271
+ }
272
+ function McpIntegrationsSection({ query }) {
273
+ const serversQuery = useMcpServers();
274
+ const createServer = useCreateMcpServer();
275
+ const deleteServer = useDeleteMcpServer();
276
+ const [dialogOpen, setDialogOpen] = useState(false);
277
+ const [initialIntegrationId, setInitialIntegrationId] = useState(null);
278
+ const [deleteTarget, setDeleteTarget] = useState(null);
279
+ const [deleteError, setDeleteError] = useState(null);
280
+ const catalog = useMemo(() => getDefaultMcpIntegrations(), []);
281
+ const normalizedQuery = query.trim().toLowerCase();
282
+ const filteredCatalog = useMemo(() => {
283
+ if (!normalizedQuery)
284
+ return catalog;
285
+ return catalog.filter((integration) => `${integration.name} ${integration.provider} ${integration.description} ${integration.useCase}`
286
+ .toLowerCase()
287
+ .includes(normalizedQuery));
288
+ }, [catalog, normalizedQuery]);
289
+ const servers = [
290
+ ...(serversQuery.data?.user ?? []),
291
+ ...(serversQuery.data?.org ?? []),
292
+ ];
293
+ const connectedUrls = new Set(servers
294
+ .filter((server) => server.status.state === "connected")
295
+ .map((server) => compareMcpUrl(server.url)));
296
+ const hasOrg = Boolean(serversQuery.data?.orgId);
297
+ const canCreateOrgMcp = Boolean(hasOrg &&
298
+ (serversQuery.data?.role === "owner" ||
299
+ serversQuery.data?.role === "admin"));
300
+ const openCatalog = useCallback((integrationId) => {
301
+ setInitialIntegrationId(integrationId ?? null);
302
+ setDialogOpen(true);
303
+ }, []);
304
+ const removeServer = useCallback(async (server) => {
305
+ const key = `${server.scope}:${server.id}`;
306
+ if (deleteTarget !== key) {
307
+ setDeleteTarget(key);
308
+ return;
309
+ }
310
+ setDeleteError(null);
311
+ try {
312
+ await deleteServer.mutateAsync({ id: server.id, scope: server.scope });
313
+ setDeleteTarget(null);
314
+ }
315
+ catch (error) {
316
+ setDeleteError(error instanceof Error
317
+ ? error.message
318
+ : "Could not remove agent integration.");
319
+ }
320
+ }, [deleteServer, deleteTarget]);
321
+ return (_jsxs("section", { "data-testid": "mcp-integrations", className: "space-y-5", children: [_jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between", children: [_jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(IconServer, { className: "size-4 text-muted-foreground" }), _jsx("h2", { className: "text-sm font-semibold text-foreground", children: "Agent integrations" })] }), _jsx("p", { className: "mt-1 text-xs leading-5 text-muted-foreground", children: "Give your agent tools and context from the services you use." })] }), _jsxs("button", { type: "button", onClick: () => openCatalog(), className: "inline-flex w-fit items-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground transition-colors hover:bg-primary/90", children: [_jsx(IconPlus, { className: "size-3.5" }), "Add integration"] })] }), deleteError && (_jsx("p", { className: "border-y border-destructive/20 bg-destructive/5 py-3 text-xs text-destructive", children: deleteError })), serversQuery.isError ? (_jsx("p", { className: "border-y border-destructive/20 bg-destructive/5 py-3 text-xs text-destructive", children: "Could not load connected agent integrations. The catalog is still available." })) : serversQuery.isLoading ? (_jsxs("div", { className: "space-y-3 rounded-xl border border-border/70 bg-card px-4 py-4", children: [_jsx("div", { className: "h-5 w-1/2 animate-pulse rounded bg-muted" }), _jsx("div", { className: "h-5 w-3/4 animate-pulse rounded bg-muted" })] })) : servers.length > 0 && !normalizedQuery ? (_jsxs("section", { className: "space-y-2", children: [_jsx("h3", { className: "text-sm font-semibold text-foreground", children: "Installed" }), _jsx("div", { className: "overflow-hidden rounded-xl border border-border/70 bg-card text-card-foreground", children: _jsx("div", { className: "divide-y divide-border/60 px-4", children: servers.map((server) => {
322
+ const key = `${server.scope}:${server.id}`;
323
+ const canRemove = server.scope === "user" ||
324
+ serversQuery.data?.role === "owner" ||
325
+ serversQuery.data?.role === "admin";
326
+ return (_jsxs("div", { className: "flex items-center gap-3 py-3.5", children: [_jsx("span", { className: "flex size-9 shrink-0 items-center justify-center rounded-lg border border-border/70 bg-background text-muted-foreground", children: _jsx(IconServer, { className: "size-4" }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "truncate text-sm font-medium text-foreground", children: server.name }), _jsx("span", { className: "text-[11px] text-muted-foreground", children: server.scope === "user"
327
+ ? "Personal"
328
+ : "Organization" })] }), _jsx(McpServerStatus, { server: server })] }), canRemove && (_jsx("button", { type: "button", onClick: () => void removeServer(server), disabled: deleteServer.isPending, className: "shrink-0 rounded-md border border-border px-2.5 py-1.5 text-xs font-medium text-foreground transition-colors hover:bg-accent disabled:opacity-50", children: deleteTarget === key ? "Confirm" : "Remove" }))] }, key));
329
+ }) }) })] })) : null, filteredCatalog.length > 0 && (_jsxs("div", { children: [_jsxs("div", { className: "mb-1 flex items-center justify-between gap-3", children: [_jsx("h3", { className: "text-sm font-semibold text-foreground", children: "Available integrations" }), _jsxs("span", { className: "text-xs text-muted-foreground", children: [filteredCatalog.length, " integrations"] })] }), _jsx("div", { className: "grid gap-x-8 overflow-hidden rounded-xl border border-border/70 bg-card px-4 sm:grid-cols-2", children: filteredCatalog.map((integration) => (_jsx(McpCatalogItem, { integration: integration, connected: connectedUrls.has(compareMcpUrl(integration.url)), onConnect: openCatalog }, integration.id))) })] })), filteredCatalog.length === 0 && normalizedQuery && (_jsxs("p", { className: "border-y border-border/60 py-4 text-xs text-muted-foreground", children: ["No agent integrations match \u201C", query, "\u201D."] })), _jsx(McpIntegrationDialog, { open: dialogOpen, onOpenChange: setDialogOpen, initialIntegrationId: initialIntegrationId, defaultScope: "user", canCreateOrgMcp: canCreateOrgMcp, hasOrg: hasOrg, onCreateMcpServer: (args) => createServer.mutateAsync(args) })] }));
330
+ }
331
+ export function IntegrationsPanel() {
332
+ const { statuses, loading, refetch } = useIntegrationStatus();
333
+ const [selectedPlatform, setSelectedPlatform] = useState(null);
334
+ const [query, setQuery] = useState("");
335
+ const statusMap = new Map(statuses.map((s) => [s.platform, s]));
336
+ const connectedPlatforms = PLATFORMS.filter((platform) => {
337
+ const status = statusMap.get(platform.id);
338
+ return status?.configured || status?.enabled;
339
+ });
340
+ const normalizedQuery = query.trim().toLowerCase();
341
+ const filteredPlatforms = PLATFORMS.filter((platform) => {
342
+ if (!normalizedQuery)
343
+ return true;
344
+ return `${platform.label} ${platform.description} ${platform.category}`
345
+ .toLowerCase()
346
+ .includes(normalizedQuery);
347
+ });
348
+ const mcpCatalogMatches = getDefaultMcpIntegrations().some((integration) => normalizedQuery
349
+ ? `${integration.name} ${integration.provider} ${integration.description} ${integration.useCase}`
350
+ .toLowerCase()
351
+ .includes(normalizedQuery)
352
+ : true);
353
+ if (selectedPlatform) {
354
+ return (_jsx(IntegrationDetail, { platform: selectedPlatform, serverStatus: statusMap.get(selectedPlatform.id), onBack: () => setSelectedPlatform(null), onRefresh: refetch }));
355
+ }
356
+ return (_jsxs("div", { className: "w-full space-y-8", children: [_jsxs("div", { className: "flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-semibold tracking-[-0.04em] text-foreground", children: "Integrations" }), _jsx("p", { className: "mt-1.5 max-w-2xl text-sm leading-6 text-muted-foreground", children: "Connect the tools your agent can use to gather context, take action, and meet your team where work already happens." })] }), _jsxs("label", { className: "relative block w-full lg:max-w-xs", children: [_jsx(IconSearch, { className: "pointer-events-none absolute start-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" }), _jsx("input", { type: "search", value: query, onChange: (event) => setQuery(event.target.value), placeholder: "Search integrations", "aria-label": "Search integrations", className: "h-9 w-full rounded-lg border border-border bg-background ps-9 pe-3 text-sm text-foreground outline-none transition-colors placeholder:text-muted-foreground focus:border-foreground/30 focus:ring-2 focus:ring-accent/40" })] })] }), _jsx(McpIntegrationsSection, { query: normalizedQuery }), loading ? (_jsx("div", { className: "grid gap-3 sm:grid-cols-2", children: [0, 1, 2, 3].map((item) => (_jsx("div", { className: "h-28 animate-pulse rounded-xl border border-border bg-muted/30" }, item))) })) : (_jsxs(_Fragment, { children: [!normalizedQuery && connectedPlatforms.length > 0 && (_jsxs("section", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-baseline justify-between gap-3", children: [_jsx("h2", { className: "text-sm font-semibold text-foreground", children: "Connected" }), _jsxs("span", { className: "text-xs text-muted-foreground", children: [connectedPlatforms.length, " connected"] })] }), _jsx("div", { className: "grid gap-3 sm:grid-cols-2", children: connectedPlatforms.map((platform) => (_jsx(IntegrationGalleryCard, { platform: platform, status: statusMap.get(platform.id), onSelect: setSelectedPlatform }, platform.id))) })] })), ["Messaging", "Workspace tools", "Agent clients"].map((category) => {
357
+ const platforms = filteredPlatforms.filter((platform) => platform.category === category &&
358
+ (!connectedPlatforms.includes(platform) || normalizedQuery));
359
+ if (platforms.length === 0)
360
+ return null;
361
+ return (_jsxs("section", { className: "mt-8 space-y-3 first:mt-0", children: [_jsx("h2", { className: "text-sm font-semibold text-foreground", children: category }), _jsx("div", { className: "grid gap-3 sm:grid-cols-2", children: platforms.map((platform) => (_jsx(IntegrationGalleryCard, { platform: platform, status: statusMap.get(platform.id), onSelect: setSelectedPlatform }, platform.id))) })] }, category));
362
+ }), filteredPlatforms.length === 0 && !mcpCatalogMatches && (_jsxs("div", { className: "rounded-xl border border-dashed border-border p-8 text-center", children: [_jsx("p", { className: "text-sm font-medium text-foreground", children: "No integrations found" }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "Try a different tool or category." })] }))] }))] }));
363
+ }
220
364
  //# sourceMappingURL=IntegrationsPanel.js.map
@@ -1,12 +1,16 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Skeleton } from "@agent-native/toolkit/ui/skeleton";
3
- import { IconArrowRight, IconBrandGithub, IconCheck, IconExternalLink, IconInfoCircle, IconKey, IconLoader2, } from "@tabler/icons-react";
3
+ import { IconArrowRight, IconBrandGithub, IconCheck, IconExternalLink, IconInfoCircle, IconKey, IconLoader2, IconPlugConnected, IconSearch, } from "@tabler/icons-react";
4
4
  import React, { useMemo, useState } from "react";
5
5
  import { appPath } from "../api-path.js";
6
6
  import { Tooltip, TooltipContent, TooltipTrigger, } from "../components/ui/tooltip.js";
7
+ import { buildMcpOAuthStartUrl, filterMcpIntegrations, getDefaultMcpIntegrations, navigateToMcpOAuthStart, } from "../resources/mcp-integration-catalog.js";
8
+ import { McpIntegrationDialog } from "../resources/McpIntegrationDialog.js";
9
+ import { formatMcpServerError, useCreateMcpServer, useMcpServers, } from "../resources/use-mcp-servers.js";
7
10
  import { useBuilderConnectFlow } from "../settings/useBuilderStatus.js";
8
11
  import { cn } from "../utils.js";
9
12
  import { useOnboarding } from "./use-onboarding.js";
13
+ import { useOnboardingPreviewMode } from "./use-preview-mode.js";
10
14
  const BUILDER_MORE_SERVICES = [
11
15
  "Voice input",
12
16
  "Background agents",
@@ -18,14 +22,38 @@ const BUILDER_MORE_SERVICES = [
18
22
  "Embeddings",
19
23
  ];
20
24
  export function FirstRunOnboarding() {
21
- const { firstRun, loading, error, profile, completeFirstRun } = useOnboarding();
25
+ const previewMode = useOnboardingPreviewMode();
26
+ const { firstRun, loading, error, profile, completeFirstRun } = useOnboarding({ preview: previewMode });
22
27
  const [screen, setScreen] = useState("intro");
23
- const showReady = () => setScreen("ready");
28
+ const [integrationQuery, setIntegrationQuery] = useState("");
29
+ const [integrationDialogId, setIntegrationDialogId] = useState(null);
30
+ const [connectingIntegrationId, setConnectingIntegrationId] = useState(null);
31
+ const [connectError, setConnectError] = useState(null);
32
+ const mcpCatalog = useMemo(() => getDefaultMcpIntegrations(), []);
33
+ const mcpServersQuery = useMcpServers();
34
+ const createMcpServer = useCreateMcpServer();
35
+ const mcpIntegrations = useMemo(() => filterMcpIntegrations(integrationQuery, mcpCatalog), [integrationQuery, mcpCatalog]);
36
+ const connectedUrls = useMemo(() => {
37
+ if (previewMode)
38
+ return new Set();
39
+ const servers = [
40
+ ...(mcpServersQuery.data?.user ?? []),
41
+ ...(mcpServersQuery.data?.org ?? []),
42
+ ];
43
+ return new Set(servers
44
+ .filter((server) => server.status.state === "connected")
45
+ .map((server) => compareUrl(server.url)));
46
+ }, [mcpServersQuery.data, previewMode]);
47
+ const hasOrg = Boolean(mcpServersQuery.data?.orgId);
48
+ const canCreateOrgMcp = Boolean(hasOrg &&
49
+ (mcpServersQuery.data?.role === "owner" ||
50
+ mcpServersQuery.data?.role === "admin"));
51
+ const showTools = () => setScreen("tools");
24
52
  const connectFlow = useBuilderConnectFlow({
25
- enabled: firstRun,
53
+ enabled: firstRun && !previewMode,
26
54
  trackingSource: "first_run_onboarding",
27
55
  trackingFlow: "connect_llm",
28
- onConnected: showReady,
56
+ onConnected: showTools,
29
57
  });
30
58
  if (!firstRun)
31
59
  return null;
@@ -37,8 +65,12 @@ export function FirstRunOnboarding() {
37
65
  }
38
66
  const builderCapabilities = profile.capabilities.filter((capability) => capability.builderIncluded);
39
67
  const handleBuilder = () => {
68
+ if (previewMode) {
69
+ setScreen("tools");
70
+ return;
71
+ }
40
72
  if (connectFlow.hasFetchedStatus && connectFlow.configured) {
41
- showReady();
73
+ showTools();
42
74
  return;
43
75
  }
44
76
  setScreen("connecting");
@@ -49,18 +81,66 @@ export function FirstRunOnboarding() {
49
81
  };
50
82
  const handleOpenSettings = async () => {
51
83
  window.dispatchEvent(new CustomEvent("agent-panel:open-settings", {
52
- detail: { section: "connections" },
84
+ detail: { section: "integrations" },
53
85
  }));
54
86
  await completeFirstRun();
55
87
  };
56
88
  const handleFinish = async () => {
57
89
  await completeFirstRun();
58
90
  };
91
+ const returnUrl = typeof window === "undefined"
92
+ ? "/"
93
+ : window.location.pathname +
94
+ window.location.search +
95
+ window.location.hash;
96
+ const connectIntegration = async (integration) => {
97
+ if (previewMode) {
98
+ setScreen("ready");
99
+ return;
100
+ }
101
+ setConnectError(null);
102
+ if (connectedUrls.has(compareUrl(integration.url)) ||
103
+ connectingIntegrationId === integration.id) {
104
+ return;
105
+ }
106
+ if (integration.authMode === "none" &&
107
+ integration.connectionMode === "direct") {
108
+ setConnectingIntegrationId(integration.id);
109
+ try {
110
+ await createMcpServer.mutateAsync({
111
+ scope: "user",
112
+ name: integration.name,
113
+ url: integration.url,
114
+ description: integration.description,
115
+ });
116
+ }
117
+ catch (error) {
118
+ setConnectError(formatMcpServerError(error instanceof Error ? error.message : String(error)));
119
+ }
120
+ finally {
121
+ setConnectingIntegrationId(null);
122
+ }
123
+ return;
124
+ }
125
+ if (integration.authMode === "oauth" &&
126
+ integration.connectionMode === "oauth" &&
127
+ integration.availability === "ready") {
128
+ navigateToMcpOAuthStart(appPath(buildMcpOAuthStartUrl({
129
+ name: integration.name,
130
+ url: integration.url,
131
+ description: integration.description,
132
+ scope: "user",
133
+ returnUrl,
134
+ })));
135
+ return;
136
+ }
137
+ setIntegrationDialogId(integration.id);
138
+ };
59
139
  if (screen === "intro") {
60
140
  return (_jsx(OnboardingShell, { profile: profile, screen: "intro", children: _jsxs("div", { className: "mx-auto flex w-full max-w-lg flex-col items-center text-center", children: [_jsxs("h1", { className: "text-3xl font-semibold tracking-[-0.05em] sm:text-4xl", children: ["Free forever.", _jsx("br", {}), _jsx("span", { className: "text-primary", children: "Open source for life." })] }), _jsxs("div", { className: "mt-7 grid w-full gap-2 text-left sm:grid-cols-3", children: [_jsxs("div", { className: "rounded-lg border border-border bg-card px-3 py-3", children: [_jsx("p", { className: "text-xs font-medium", children: "Fully customizable" }), _jsx("p", { className: "mt-1 text-[11px] leading-4 text-muted-foreground", children: "Change the UI, code, and behavior." })] }), _jsxs("div", { className: "rounded-lg border border-border bg-card px-3 py-3", children: [_jsx("p", { className: "text-xs font-medium", children: "Bring your own keys" }), _jsx("p", { className: "mt-1 text-[11px] leading-4 text-muted-foreground", children: "Use your own providers and accounts." })] }), _jsxs("div", { className: "rounded-lg border border-border bg-card px-3 py-3", children: [_jsx("p", { className: "text-xs font-medium", children: "Build your own" }), _jsx("p", { className: "mt-1 text-[11px] leading-4 text-muted-foreground", children: "Mix and match toolkit pieces in your own apps." })] })] }), _jsxs("button", { type: "button", className: cn(primaryButtonClass, "mt-6"), onClick: () => setScreen("choice"), children: ["Continue", _jsx(IconArrowRight, { size: 15 })] }), _jsxs("a", { href: "https://github.com/builderio/agent-native", target: "_blank", rel: "noreferrer", className: "mt-3 inline-flex items-center gap-1.5 text-xs text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: [_jsx(IconBrandGithub, { size: 14 }), _jsx("span", { children: "View source" }), _jsx(IconExternalLink, { size: 13 })] })] }) }));
61
141
  }
62
142
  if (screen === "choice") {
63
- return (_jsx(OnboardingShell, { profile: profile, screen: "choice", children: _jsxs("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-4", children: [_jsx("h1", { className: "text-center text-xl font-semibold tracking-[-0.04em] sm:text-2xl", children: "Choose your setup." }), _jsxs("div", { className: "grid gap-3 sm:grid-cols-2", children: [_jsxs("section", { className: "rounded-xl border border-primary/50 bg-primary/[0.06] p-4 shadow-sm", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-sm font-semibold", children: "Connect Builder.io" }), _jsxs("p", { className: "mt-1 max-w-xs text-xs leading-5 text-muted-foreground", children: ["One click connects", " ", _jsx("a", { href: "https://www.builder.io/", target: "_blank", rel: "noreferrer", className: "text-foreground underline decoration-border underline-offset-2 hover:decoration-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: "Builder.io's free tier" }), " ", "with the services this app needs."] })] }), _jsx(IconArrowRight, { className: "mt-0.5 text-primary", size: 17 })] }), _jsxs("div", { className: "mt-5 border-t border-primary/15 pt-3", children: [_jsx("p", { className: "text-[11px] font-medium text-muted-foreground", children: "Includes on the free tier" }), _jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-1.5 gap-y-1 text-[11px]", children: [builderCapabilities.map((capability, index) => (_jsxs(React.Fragment, { children: [index > 0 && (_jsx("span", { "aria-hidden": "true", className: "text-muted-foreground", children: "\u00B7" })), _jsx("span", { children: capability.label })] }, capability.id))), _jsx("span", { "aria-hidden": "true", className: "text-muted-foreground", children: "\u00B7" }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: "text-primary underline-offset-2 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", "aria-label": `See ${BUILDER_MORE_SERVICES.length} more Builder.io services`, children: ["+", BUILDER_MORE_SERVICES.length, " more"] }) }), _jsxs(TooltipContent, { side: "top", className: "max-w-sm text-xs", children: [_jsx("p", { className: "font-medium", children: "Also included with Builder.io" }), _jsx("p", { className: "mt-1 leading-5", children: BUILDER_MORE_SERVICES.join(" · ") })] })] })] })] }), _jsxs("button", { type: "button", "data-testid": "first-run-connect-builder", className: cn(primaryButtonClass, "mt-5 w-full"), onClick: handleBuilder, children: ["Connect Builder.io", _jsx(IconArrowRight, { size: 15 })] })] }), _jsxs("div", { role: "button", tabIndex: 0, "aria-label": "Use my own keys", "data-testid": "first-run-use-own-keys", className: "rounded-xl border border-border bg-card p-4 text-left transition-colors hover:border-foreground/30 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: () => setScreen("manual"), onKeyDown: (event) => {
143
+ return (_jsx(OnboardingShell, { profile: profile, screen: "choice", children: _jsxs("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-4", children: [_jsx("h1", { className: "text-center text-xl font-semibold tracking-[-0.04em] sm:text-2xl", children: "Choose your setup." }), _jsxs("div", { className: "grid gap-3 sm:grid-cols-2", children: [_jsxs("section", { className: "rounded-xl border border-primary/50 bg-primary/[0.06] p-4 shadow-sm", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-sm font-semibold", children: "Connect Builder.io free credits" }), _jsxs("p", { className: "mt-1 max-w-xs text-xs leading-5 text-muted-foreground", children: ["One click connects", " ", _jsx("a", { href: "https://www.builder.io/", target: "_blank", rel: "noreferrer", className: "text-foreground underline decoration-border underline-offset-2 hover:decoration-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: "Builder.io free credits" }), " ", "with the services this app needs."] })] }), _jsx(IconArrowRight, { className: "mt-0.5 text-primary", size: 17 })] }), _jsxs("div", { className: "mt-5 border-t border-primary/15 pt-3", children: [_jsx("p", { className: "text-[11px] font-medium text-muted-foreground", children: "Included with Builder.io free credits" }), _jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-1.5 gap-y-1 text-[11px]", children: [builderCapabilities.map((capability, index) => (_jsxs(React.Fragment, { children: [index > 0 && (_jsx("span", { "aria-hidden": "true", className: "text-muted-foreground", children: "\u00B7" })), _jsx("span", { children: capability.label })] }, capability.id))), _jsx("span", { "aria-hidden": "true", className: "text-muted-foreground", children: "\u00B7" }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: "text-primary underline-offset-2 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", "aria-label": `See ${BUILDER_MORE_SERVICES.length} more services included with Builder.io free credits`, children: ["+", BUILDER_MORE_SERVICES.length, " more"] }) }), _jsxs(TooltipContent, { side: "top", className: "max-w-sm text-xs", children: [_jsx("p", { className: "font-medium", children: "Also included with Builder.io free credits" }), _jsx("p", { className: "mt-1 leading-5", children: BUILDER_MORE_SERVICES.join(" · ") })] })] })] })] }), _jsxs("button", { type: "button", "data-testid": "first-run-connect-builder", className: cn(primaryButtonClass, "mt-5 w-full"), onClick: handleBuilder, children: ["Connect Builder.io free credits", _jsx(IconArrowRight, { size: 15 })] })] }), _jsxs("div", { role: "button", tabIndex: 0, "aria-label": "Use my own keys", "data-testid": "first-run-use-own-keys", className: "rounded-xl border border-border bg-card p-4 text-left transition-colors hover:border-foreground/30 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: () => setScreen("manual"), onKeyDown: (event) => {
64
144
  if (event.key !== "Enter" && event.key !== " ")
65
145
  return;
66
146
  event.preventDefault();
@@ -68,26 +148,61 @@ export function FirstRunOnboarding() {
68
148
  }, children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-sm font-semibold", children: "Use my own keys" }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "See what this app needs" })] }), _jsx(IconKey, { className: "text-muted-foreground", size: 17 })] }), _jsx(CapabilityList, { capabilities: profile.capabilities, compact: true, className: "mt-5 border-t border-border pt-3" })] })] })] }) }));
69
149
  }
70
150
  if (screen === "manual") {
71
- return (_jsx(OnboardingShell, { profile: profile, screen: "choice", children: _jsxs("div", { className: "mx-auto flex w-full max-w-xl flex-col gap-4", children: [_jsxs("div", { children: [_jsx("button", { type: "button", className: "mb-4 text-xs text-muted-foreground hover:text-foreground", onClick: () => setScreen("choice"), children: "Back" }), _jsx("h1", { className: "text-xl font-semibold tracking-[-0.04em] sm:text-2xl", children: "Your keys" })] }), _jsxs("div", { className: "rounded-xl border border-border bg-card p-4", children: [_jsx(CapabilityList, { capabilities: profile.capabilities }), _jsxs("div", { className: "mt-5 flex flex-col-reverse gap-2 border-t border-border pt-4 sm:flex-row sm:justify-between", children: [_jsx("button", { type: "button", className: secondaryButtonClass, onClick: () => setScreen("choice"), children: "Back" }), _jsxs("button", { type: "button", className: primaryButtonClass, onClick: handleOpenSettings, children: ["Open key settings", _jsx(IconArrowRight, { size: 15 })] })] })] })] }) }));
151
+ return (_jsx(OnboardingShell, { profile: profile, screen: "choice", children: _jsxs("div", { className: "mx-auto flex w-full max-w-xl flex-col gap-4", children: [_jsxs("div", { children: [_jsx("button", { type: "button", className: "mb-4 text-xs text-muted-foreground hover:text-foreground", onClick: () => setScreen("choice"), children: "Back" }), _jsx("h1", { className: "text-xl font-semibold tracking-[-0.04em] sm:text-2xl", children: "Your keys" })] }), _jsxs("div", { className: "rounded-xl border border-border bg-card p-4", children: [_jsx(CapabilityList, { capabilities: profile.capabilities }), _jsxs("div", { className: "mt-5 flex flex-col-reverse gap-2 border-t border-border pt-4 sm:flex-row sm:justify-between", children: [_jsx("button", { type: "button", className: secondaryButtonClass, onClick: () => setScreen("choice"), children: "Back" }), _jsxs("button", { type: "button", className: primaryButtonClass, onClick: handleOpenSettings, children: ["Open key settings", _jsx(IconArrowRight, { size: 15 })] }), _jsx("button", { type: "button", className: secondaryButtonClass, onClick: () => setScreen("tools"), children: "Continue to tools" })] })] })] }) }));
152
+ }
153
+ if (screen === "tools") {
154
+ return (_jsxs(OnboardingShell, { profile: profile, screen: "tools", footer: _jsxs("div", { "data-testid": "onboarding-tools-footer", className: "mx-auto flex w-full max-w-3xl flex-wrap items-center justify-end gap-2", children: [_jsx("button", { type: "button", className: secondaryButtonClass, onClick: handleFinish, children: "Skip for now" }), _jsxs("button", { type: "button", className: primaryButtonClass, onClick: handleFinish, children: ["Continue", _jsx(IconArrowRight, { size: 15 })] })] }), children: [_jsxs("div", { className: "mx-auto flex w-full max-w-4xl flex-col gap-5", children: [_jsxs("div", { className: "text-center", children: [_jsx("div", { className: "mx-auto flex size-11 items-center justify-center rounded-2xl bg-primary/10 text-primary", children: _jsx(IconPlugConnected, { size: 22 }) }), _jsx("h1", { className: "mt-5 text-2xl font-semibold tracking-[-0.05em] sm:text-3xl", children: "This app is an agent." }), _jsx("p", { className: "mt-3 text-sm leading-6 text-muted-foreground", children: "Search the catalog and connect what you need. The onboarding stays open while you add integrations." })] }), _jsxs("div", { className: "flex flex-col gap-4", children: [_jsxs("div", { className: "flex flex-col gap-3 border-b border-border pb-4", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx("p", { className: "text-sm font-medium text-foreground", children: "Agent integrations" }), _jsxs("span", { className: "text-xs text-muted-foreground", children: [mcpIntegrations.length, " of ", mcpCatalog.length] })] }), _jsxs("label", { className: "relative", children: [_jsx(IconSearch, { className: "pointer-events-none absolute start-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" }), _jsx("input", { value: integrationQuery, onChange: (event) => setIntegrationQuery(event.target.value), className: "h-9 w-full rounded-md border border-border bg-background pe-3 ps-8 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-ring", placeholder: "Search integrations", "aria-label": "Search integrations" })] }), connectError && (_jsx("p", { className: "text-xs leading-5 text-destructive", children: connectError }))] }), _jsx("div", { children: mcpIntegrations.length > 0 ? (_jsx("div", { className: "grid gap-x-8 sm:grid-cols-2", children: mcpIntegrations.map((integration) => (_jsx(McpIntegrationCard, { integration: integration, connected: connectedUrls.has(compareUrl(integration.url)), busy: connectingIntegrationId === integration.id, onConnect: connectIntegration }, integration.id))) })) : (_jsx("div", { className: "border-y border-dashed border-border px-4 py-8 text-center text-xs text-muted-foreground", children: "No integrations match." })) })] })] }), integrationDialogId && (_jsx(McpIntegrationDialog, { open: true, onOpenChange: (open) => {
155
+ if (!open)
156
+ setIntegrationDialogId(null);
157
+ }, initialIntegrationId: integrationDialogId, defaultScope: canCreateOrgMcp ? "org" : "user", canCreateOrgMcp: canCreateOrgMcp, hasOrg: hasOrg, onCreateMcpServer: createMcpServer.mutateAsync }))] }));
72
158
  }
73
159
  if (screen === "connecting") {
74
- return (_jsx(OnboardingShell, { profile: profile, screen: "choice", children: _jsxs("div", { className: "mx-auto flex w-full max-w-md flex-col items-center text-center", children: [_jsx("div", { className: "flex size-10 items-center justify-center rounded-full bg-primary/10 text-primary", children: _jsx(IconLoader2, { className: "animate-spin", size: 19 }) }), _jsx("h1", { className: "mt-5 text-xl font-semibold tracking-[-0.04em]", children: "Connecting Builder.io" }), _jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: "Finish the one-click connection in the new window." }), _jsxs("div", { className: "mt-7 w-full rounded-xl border border-border bg-card p-4 text-left", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx(Skeleton, { className: "h-3 w-28" }), _jsx(Skeleton, { className: "h-5 w-16 rounded-full" })] }), _jsx(Skeleton, { className: "mt-4 h-8 w-full" }), _jsxs("div", { className: "mt-3 grid grid-cols-3 gap-2", children: [_jsx(Skeleton, { className: "h-7 w-full" }), _jsx(Skeleton, { className: "h-7 w-full" }), _jsx(Skeleton, { className: "h-7 w-full" })] })] }), connectFlow.error && (_jsxs("div", { className: "mt-4 flex flex-col items-center gap-2", children: [_jsx("p", { className: "text-xs text-destructive", children: connectFlow.error }), _jsx("button", { type: "button", className: secondaryButtonClass, onClick: () => setScreen("choice"), children: "Try again" })] }))] }) }));
160
+ return (_jsx(OnboardingShell, { profile: profile, screen: "choice", children: _jsxs("div", { className: "mx-auto flex w-full max-w-md flex-col items-center text-center", children: [_jsx("div", { className: "flex size-10 items-center justify-center rounded-full bg-primary/10 text-primary", children: _jsx(IconLoader2, { className: "animate-spin", size: 19 }) }), _jsx("h1", { className: "mt-5 text-xl font-semibold tracking-[-0.04em]", children: "Connecting Builder.io free credits" }), _jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: "Finish the one-click connection in the new window." }), _jsxs("div", { className: "mt-7 w-full rounded-xl border border-border bg-card p-4 text-left", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx(Skeleton, { className: "h-3 w-28" }), _jsx(Skeleton, { className: "h-5 w-16 rounded-full" })] }), _jsx(Skeleton, { className: "mt-4 h-8 w-full" }), _jsxs("div", { className: "mt-3 grid grid-cols-3 gap-2", children: [_jsx(Skeleton, { className: "h-7 w-full" }), _jsx(Skeleton, { className: "h-7 w-full" }), _jsx(Skeleton, { className: "h-7 w-full" })] })] }), connectFlow.error && (_jsxs("div", { className: "mt-4 flex flex-col items-center gap-2", children: [_jsx("p", { className: "text-xs text-destructive", children: connectFlow.error }), _jsx("button", { type: "button", className: secondaryButtonClass, onClick: () => setScreen("choice"), children: "Try again" })] }))] }) }));
75
161
  }
76
- return (_jsx(OnboardingShell, { profile: profile, screen: "choice", children: _jsxs("div", { className: "mx-auto flex w-full max-w-md flex-col items-center text-center", children: [_jsx("div", { className: "flex size-10 items-center justify-center rounded-full bg-primary/10 text-primary", children: _jsx(IconCheck, { size: 20 }) }), _jsx("h1", { className: "mt-5 text-xl font-semibold tracking-[-0.04em]", children: "Ready to go." }), _jsxs("button", { type: "button", "data-testid": "first-run-open-app", className: cn(primaryButtonClass, "mt-7"), onClick: handleFinish, children: ["Open app", _jsx(IconArrowRight, { size: 15 })] })] }) }));
162
+ return (_jsx(OnboardingShell, { profile: profile, screen: "ready", children: _jsxs("div", { className: "mx-auto flex w-full max-w-2xl flex-col items-center text-center", children: [_jsx("div", { className: "flex size-12 items-center justify-center rounded-2xl bg-primary/10 text-primary", children: _jsx(IconCheck, { size: 20 }) }), _jsx("h1", { className: "mt-5 text-xl font-semibold tracking-[-0.04em]", children: "Your agent is ready." }), _jsx("p", { className: "mt-2 max-w-md text-sm leading-6 text-muted-foreground", children: "Start with a chat, then connect more tools whenever you need them." }), _jsx("div", { className: "mt-7 grid w-full gap-2 text-left sm:grid-cols-3", children: [
163
+ ["Chat + actions", "Ask your agent to work across the app."],
164
+ ["Agent integrations", "Connect tools from Settings anytime."],
165
+ [
166
+ "Flexible providers",
167
+ "Use Builder.io free credits or your own keys.",
168
+ ],
169
+ ].map(([title, description]) => (_jsxs("div", { className: "rounded-xl bg-card px-4 py-4 ring-1 ring-border/70", children: [_jsx("span", { className: "flex size-7 items-center justify-center rounded-full bg-primary/10 text-primary", children: _jsx(IconCheck, { size: 14 }) }), _jsx("p", { className: "mt-3 text-sm font-medium", children: title }), _jsx("p", { className: "mt-1 text-xs leading-5 text-muted-foreground", children: description })] }, title))) }), _jsxs("button", { type: "button", "data-testid": "first-run-open-app", className: cn(primaryButtonClass, "mt-7"), onClick: handleFinish, children: ["Open app", _jsx(IconArrowRight, { size: 15 })] })] }) }));
77
170
  }
78
- function OnboardingShell({ profile, screen, children, }) {
79
- return (_jsxs("div", { className: "fixed inset-0 z-[100] flex min-h-screen flex-col bg-background text-foreground", "data-onboarding-screen": screen, role: "dialog", "aria-modal": "true", "aria-label": `${profile?.appName ?? "Your app"} setup`, children: [_jsxs("header", { className: "flex items-center justify-between border-b border-border px-5 py-4 text-xs text-muted-foreground sm:px-8", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("img", { src: appPath("/agent-native-icon-dark.svg"), alt: "", "aria-hidden": "true", className: "h-4 w-auto shrink-0" }), _jsx("span", { className: "font-medium text-foreground", children: profile?.appName ?? "Your app" })] }), _jsx("span", { children: screen === "intro" ? "1 / 2" : "2 / 2" })] }), _jsx("div", { className: "h-0.5 bg-muted", children: _jsx("div", { className: "h-full bg-primary transition-[width] duration-200", style: { width: screen === "intro" ? "50%" : "100%" } }) }), _jsx("main", { className: "flex min-h-0 flex-1 items-center overflow-y-auto px-5 py-10 sm:px-8", children: _jsx("div", { className: "mx-auto w-full max-w-3xl", children: children }) })] }));
171
+ function OnboardingShell({ profile, screen, footer, children, }) {
172
+ return (_jsxs("div", { className: "fixed inset-0 z-[100] flex h-full min-h-0 flex-col bg-background text-foreground", "data-onboarding-screen": screen, role: "dialog", "aria-modal": "true", "aria-label": `${profile?.appName ?? "Your app"} setup`, children: [_jsx("div", { className: "h-0.5 shrink-0 bg-muted", "data-testid": "onboarding-progress", children: _jsx("div", { className: "h-full bg-primary transition-[width] duration-200", style: {
173
+ width: screen === "intro"
174
+ ? "33.33%"
175
+ : screen === "tools" || screen === "ready"
176
+ ? "100%"
177
+ : "66.66%",
178
+ } }) }), _jsx("main", { className: cn("flex min-h-0 flex-1 overflow-y-auto px-5 sm:px-8", screen === "tools" ? "items-start py-8" : "items-center py-10"), children: _jsx("div", { className: "mx-auto w-full max-w-3xl", children: children }) }), footer && (_jsx("footer", { className: "shrink-0 border-t border-border bg-background/95 px-5 py-3 backdrop-blur-sm sm:px-8", children: footer }))] }));
80
179
  }
81
180
  function OnboardingSkeleton() {
82
- return (_jsxs("div", { className: "fixed inset-0 z-[100] flex min-h-screen flex-col bg-background px-5 py-5 sm:px-8", "data-onboarding-loading": "true", "aria-busy": "true", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx(Skeleton, { className: "h-4 w-20" }), _jsx(Skeleton, { className: "h-3 w-8" })] }), _jsx(Skeleton, { className: "mt-5 h-0.5 w-full" }), _jsxs("div", { className: "mx-auto flex w-full max-w-lg flex-1 flex-col items-center justify-center", children: [_jsx(Skeleton, { className: "h-10 w-64" }), _jsx(Skeleton, { className: "mt-3 h-10 w-52" }), _jsx(Skeleton, { className: "mt-7 h-3 w-44" }), _jsx(Skeleton, { className: "mt-7 h-10 w-24 rounded-lg" })] })] }));
181
+ return (_jsxs("div", { className: "fixed inset-0 z-[100] flex h-full min-h-0 flex-col bg-background", "data-onboarding-loading": "true", "aria-busy": "true", children: [_jsx(Skeleton, { className: "h-0.5 w-full shrink-0" }), _jsxs("div", { className: "mx-auto flex w-full max-w-lg flex-1 flex-col items-center justify-center px-5 sm:px-8", children: [_jsx(Skeleton, { className: "h-10 w-64" }), _jsx(Skeleton, { className: "mt-3 h-10 w-52" }), _jsx(Skeleton, { className: "mt-7 h-3 w-44" }), _jsx(Skeleton, { className: "mt-7 h-10 w-24 rounded-lg" })] })] }));
83
182
  }
84
183
  function CapabilityList({ capabilities, compact = false, className, }) {
85
184
  const visibleCapabilities = useMemo(() => (compact ? capabilities.slice(0, 4) : capabilities), [capabilities, compact]);
86
- return (_jsxs("div", { className: cn("grid", className), children: [!compact && (_jsx("p", { className: "mb-2 text-xs font-medium text-muted-foreground", children: "Keys and connections" })), _jsx("div", { className: "divide-y divide-border", children: visibleCapabilities.map((capability) => (_jsx(CapabilityRow, { capability: capability, compact: compact }, capability.id))) })] }));
185
+ return (_jsxs("div", { className: cn("grid", className), children: [!compact && (_jsx("p", { className: "mb-2 text-xs font-medium text-muted-foreground", children: "Keys and integrations" })), _jsx("div", { className: "divide-y divide-border", children: visibleCapabilities.map((capability) => (_jsx(CapabilityRow, { capability: capability, compact: compact }, capability.id))) })] }));
186
+ }
187
+ function McpIntegrationCard({ integration, connected, busy, onConnect, }) {
188
+ const actionLabel = "Connect";
189
+ return (_jsxs("article", { className: "flex min-w-0 items-center gap-3 border-b border-border/70 py-3.5 sm:pe-4", children: [_jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-3", children: [_jsxs("span", { className: "relative flex size-8 shrink-0 items-center justify-center overflow-hidden rounded-md border border-border bg-card text-xs font-semibold text-muted-foreground", children: [integration.name.slice(0, 1), _jsx("img", { src: integration.logoUrl, alt: "", className: "absolute inset-0 size-full object-contain p-1", onError: (event) => {
190
+ event.currentTarget.hidden = true;
191
+ } })] }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("h3", { className: "truncate text-sm font-medium text-foreground", children: integration.name }), connected ? (_jsx("span", { className: "rounded-full border border-border bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground", children: "Connected" })) : null] }), _jsx("p", { className: "mt-1 line-clamp-2 text-[11px] leading-4 text-muted-foreground", children: integration.description })] })] }), _jsxs("button", { type: "button", onClick: () => onConnect(integration), disabled: connected || busy, "aria-label": `${actionLabel} ${integration.name}`, className: "inline-flex min-h-8 shrink-0 items-center justify-center gap-1.5 rounded-md border border-border bg-background px-3 text-[11px] font-medium text-foreground transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50", children: [busy ? _jsx(IconLoader2, { className: "animate-spin", size: 13 }) : null, connected ? "Connected" : actionLabel] })] }));
87
192
  }
88
193
  function CapabilityRow({ capability, compact, }) {
89
194
  return (_jsxs("div", { className: cn("flex items-start justify-between gap-3", compact ? "py-2" : "py-3"), children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: cn("font-medium", compact ? "text-[11px]" : "text-sm"), children: capability.label }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": `Why ${capability.label} is needed`, className: "inline-flex size-4 items-center justify-center rounded-full text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: (event) => event.stopPropagation(), onKeyDown: (event) => event.stopPropagation(), children: _jsx(IconInfoCircle, { size: 13 }) }) }), _jsx(TooltipContent, { side: "top", className: "max-w-xs text-xs", children: capability.why })] })] }), _jsx("p", { className: "mt-1 text-[11px] leading-4 text-muted-foreground", children: capability.keySummary })] }), _jsx("span", { className: cn("shrink-0 text-[10px] uppercase tracking-[0.08em]", capability.required ? "text-primary" : "text-muted-foreground"), children: capability.required ? "Required" : "Optional" })] }));
90
195
  }
91
196
  const primaryButtonClass = "inline-flex min-h-9 items-center justify-center gap-2 rounded-lg bg-primary px-4 text-xs font-medium text-primary-foreground shadow-sm transition-opacity hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring";
92
197
  const secondaryButtonClass = "inline-flex min-h-9 items-center justify-center gap-2 rounded-lg border border-border bg-background px-4 text-xs font-medium text-foreground transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring";
198
+ function compareUrl(value) {
199
+ try {
200
+ const url = new URL(value.trim());
201
+ url.hash = "";
202
+ return url.toString().replace(/\/+$/, "");
203
+ }
204
+ catch {
205
+ return value.trim().replace(/\/+$/, "");
206
+ }
207
+ }
93
208
  //# sourceMappingURL=FirstRunOnboarding.js.map
@@ -4,7 +4,7 @@
4
4
  * Subpath: `@agent-native/core/client/onboarding`
5
5
  */
6
6
  export { useOnboarding, type UseOnboardingResult } from "./use-onboarding.js";
7
- export { useOnboardingPreviewMode, ONBOARDING_PREVIEW_STORAGE_KEY, } from "./use-preview-mode.js";
7
+ export { useOnboardingPreviewMode, ONBOARDING_PREVIEW_STORAGE_KEY, ONBOARDING_PREVIEW_QUERY_PARAM, ONBOARDING_PREVIEW_QUERY_VALUE, isOnboardingPreviewQuery, } from "./use-preview-mode.js";
8
8
  export { OnboardingPanel } from "./OnboardingPanel.js";
9
9
  export { OnboardingBanner } from "./OnboardingBanner.js";
10
10
  export { SetupButton } from "./SetupButton.js";
@@ -4,7 +4,7 @@
4
4
  * Subpath: `@agent-native/core/client/onboarding`
5
5
  */
6
6
  export { useOnboarding } from "./use-onboarding.js";
7
- export { useOnboardingPreviewMode, ONBOARDING_PREVIEW_STORAGE_KEY, } from "./use-preview-mode.js";
7
+ export { useOnboardingPreviewMode, ONBOARDING_PREVIEW_STORAGE_KEY, ONBOARDING_PREVIEW_QUERY_PARAM, ONBOARDING_PREVIEW_QUERY_VALUE, isOnboardingPreviewQuery, } from "./use-preview-mode.js";
8
8
  export { OnboardingPanel } from "./OnboardingPanel.js";
9
9
  export { OnboardingBanner } from "./OnboardingBanner.js";
10
10
  export { SetupButton } from "./SetupButton.js";
@@ -15,8 +15,11 @@ export function useOnboarding(options = {}) {
15
15
  const [loading, setLoading] = useState(true);
16
16
  const [error, setError] = useState(null);
17
17
  const [dismissed, setDismissed] = useState(false);
18
- const [firstRun, setFirstRun] = useState(hasFirstRunCookie);
18
+ const [firstRun, setFirstRun] = useState(() => preview || hasFirstRunCookie());
19
19
  const mountedRef = useRef(true);
20
+ useEffect(() => {
21
+ setFirstRun(preview || hasFirstRunCookie());
22
+ }, [preview]);
20
23
  const fetchAll = useCallback(async () => {
21
24
  try {
22
25
  const stepsUrl = agentNativePath(preview
@@ -99,6 +102,13 @@ export function useOnboarding(options = {}) {
99
102
  await fetchAll();
100
103
  }, [fetchAll]);
101
104
  const completeFirstRun = useCallback(async () => {
105
+ if (preview) {
106
+ setFirstRun(false);
107
+ if (typeof window !== "undefined") {
108
+ window.dispatchEvent(new CustomEvent("agent-native:first-run-completed"));
109
+ }
110
+ return;
111
+ }
102
112
  const response = await fetch(agentNativePath("/_agent-native/onboarding/first-run/complete"), {
103
113
  method: "POST",
104
114
  headers: { "Content-Type": "application/json" },
@@ -113,7 +123,7 @@ export function useOnboarding(options = {}) {
113
123
  window.dispatchEvent(new CustomEvent("agent-native:first-run-completed"));
114
124
  }
115
125
  await fetchAll();
116
- }, [fetchAll]);
126
+ }, [fetchAll, preview]);
117
127
  const totalCount = steps.length;
118
128
  const completeCount = steps.filter((s) => s.complete).length;
119
129
  const allComplete = steps.filter((s) => s.required).every((s) => s.complete);
@@ -4,7 +4,11 @@
4
4
  *
5
5
  * Storage key matches the dev-overlay option id `framework-onboarding/show-as-new-user`
6
6
  * so toggling the option in the overlay automatically activates preview mode here.
7
+ * The `?onboarding=preview` query also enables it for an existing account.
7
8
  */
8
9
  export declare const ONBOARDING_PREVIEW_STORAGE_KEY = "agent-native-dev-overlay-option-framework-onboarding-show-as-new-user";
10
+ export declare const ONBOARDING_PREVIEW_QUERY_PARAM = "onboarding";
11
+ export declare const ONBOARDING_PREVIEW_QUERY_VALUE = "preview";
12
+ export declare function isOnboardingPreviewQuery(search: string): boolean;
9
13
  export declare function useOnboardingPreviewMode(): boolean;
10
14
  //# sourceMappingURL=use-preview-mode.d.ts.map
@@ -4,12 +4,21 @@
4
4
  *
5
5
  * Storage key matches the dev-overlay option id `framework-onboarding/show-as-new-user`
6
6
  * so toggling the option in the overlay automatically activates preview mode here.
7
+ * The `?onboarding=preview` query also enables it for an existing account.
7
8
  */
8
9
  import { useEffect, useState } from "react";
9
10
  export const ONBOARDING_PREVIEW_STORAGE_KEY = "agent-native-dev-overlay-option-framework-onboarding-show-as-new-user";
11
+ export const ONBOARDING_PREVIEW_QUERY_PARAM = "onboarding";
12
+ export const ONBOARDING_PREVIEW_QUERY_VALUE = "preview";
13
+ export function isOnboardingPreviewQuery(search) {
14
+ return (new URLSearchParams(search).get(ONBOARDING_PREVIEW_QUERY_PARAM) ===
15
+ ONBOARDING_PREVIEW_QUERY_VALUE);
16
+ }
10
17
  function readPreview() {
11
18
  if (typeof window === "undefined")
12
19
  return false;
20
+ if (isOnboardingPreviewQuery(window.location.search))
21
+ return true;
13
22
  try {
14
23
  return (JSON.parse(window.localStorage.getItem(ONBOARDING_PREVIEW_STORAGE_KEY) || "false") === true);
15
24
  }
@@ -38,7 +38,7 @@ function StatusBadge({ enabled, status, }) {
38
38
  }
39
39
  function ToolsSummary({ enabled, status, }) {
40
40
  if (!enabled) {
41
- return (_jsx("span", { className: "text-[12px] text-muted-foreground", children: "Disabled. Toggle it on to expose MCP tools to the agent." }));
41
+ return (_jsx("span", { className: "text-[12px] text-muted-foreground", children: "Disabled. Toggle it on to expose agent tools." }));
42
42
  }
43
43
  if (status?.state === "connected") {
44
44
  return (_jsxs("span", { className: "text-[12px] text-foreground", children: [status.toolCount, " tool", status.toolCount === 1 ? "" : "s", " exposed"] }));
@@ -46,6 +46,6 @@ function ToolsSummary({ enabled, status, }) {
46
46
  if (status?.state === "error") {
47
47
  return (_jsx("span", { className: "text-[12px] text-red-600 dark:text-red-400", children: status.error }));
48
48
  }
49
- return (_jsx("span", { className: "text-[12px] text-muted-foreground", children: "Enabled. Tools will appear after the MCP manager connects." }));
49
+ return (_jsx("span", { className: "text-[12px] text-muted-foreground", children: "Enabled. Tools will appear after the agent integration manager connects." }));
50
50
  }
51
51
  //# sourceMappingURL=BuiltinCapabilityDetail.js.map