@agent-native/core 0.167.4 → 0.168.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/brain/actions/list-sources.ts +17 -7
  3. package/corpus/templates/brain/app/components/brain/Surface.tsx +4 -2
  4. package/corpus/templates/brain/app/lib/brain.ts +13 -3
  5. package/corpus/templates/brain/server/lib/brain-health.ts +5 -8
  6. package/corpus/templates/brain/server/lib/brain.ts +1 -0
  7. package/corpus/templates/brain/server/lib/capture-sanitization.ts +5 -0
  8. package/corpus/templates/brain/server/routes/api/brain/queue/run.post.ts +3 -2
  9. package/corpus/templates/clips/desktop/src/app.tsx +11 -10
  10. package/corpus/templates/clips/desktop/src/lib/desktop-oauth-window.ts +23 -0
  11. package/corpus/templates/clips/desktop/src-tauri/src/util.rs +32 -0
  12. package/dist/client/AboutAgentNativeDialog.d.ts +5 -0
  13. package/dist/client/AboutAgentNativeDialog.js +56 -0
  14. package/dist/client/AgentPanel.d.ts +3 -1
  15. package/dist/client/AgentPanel.js +2 -2
  16. package/dist/client/CommandMenu.d.ts +6 -1
  17. package/dist/client/CommandMenu.js +46 -3
  18. package/dist/client/EnvironmentBadge.js +4 -1
  19. package/dist/client/agent-native-version.d.ts +12 -0
  20. package/dist/client/agent-native-version.js +36 -0
  21. package/dist/client/agent-page/AgentTabsPage.d.ts +4 -1
  22. package/dist/client/agent-page/AgentTabsPage.js +2 -2
  23. package/dist/client/integrations/IntegrationConnectionChoice.d.ts +4 -1
  24. package/dist/client/integrations/IntegrationConnectionChoice.js +6 -2
  25. package/dist/client/onboarding/FirstRunOnboarding.js +9 -5
  26. package/dist/client/resources/McpIntegrationDialog.d.ts +3 -1
  27. package/dist/client/resources/McpIntegrationDialog.js +181 -112
  28. package/dist/client/resources/mcp-integration-catalog.d.ts +1 -0
  29. package/dist/client/resources/mcp-integration-catalog.js +5 -2
  30. package/dist/collab/struct-routes.d.ts +1 -1
  31. package/dist/config.d.ts +3 -1
  32. package/dist/config.js +14 -9
  33. package/dist/localization/core-messages/ar-SA.js +6 -0
  34. package/dist/localization/core-messages/de-DE.js +6 -0
  35. package/dist/localization/core-messages/en-US.d.ts +6 -0
  36. package/dist/localization/core-messages/en-US.js +6 -0
  37. package/dist/localization/core-messages/es-ES.js +6 -0
  38. package/dist/localization/core-messages/fr-FR.js +6 -0
  39. package/dist/localization/core-messages/hi-IN.js +6 -0
  40. package/dist/localization/core-messages/ja-JP.js +6 -0
  41. package/dist/localization/core-messages/ko-KR.js +6 -0
  42. package/dist/localization/core-messages/pt-BR.js +6 -0
  43. package/dist/localization/core-messages/zh-CN.js +6 -0
  44. package/dist/localization/core-messages/zh-TW.js +6 -0
  45. package/dist/localization/core-messages.d.ts +6 -0
  46. package/dist/localization/default-messages.d.ts +9 -0
  47. package/dist/localization/default-messages.js +9 -0
  48. package/dist/observability/routes.d.ts +3 -3
  49. package/dist/provider-api/actions/custom-provider-registration.d.ts +4 -4
  50. package/dist/provider-api/actions/provider-api.d.ts +8 -8
  51. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  52. package/dist/vite/agent-native-config-loader.js +1 -1
  53. package/dist/vite/client.js +9 -8
  54. package/dist/vite/package-versions.d.ts +1 -0
  55. package/dist/vite/package-versions.js +97 -0
  56. package/docs/content/agent-native-config.mdx +55 -31
  57. package/docs/content/environment-variables.mdx +51 -14
  58. package/package.json +1 -1
@@ -3,7 +3,10 @@ import type { ResourceView } from "../resources/ResourcesPanel.js";
3
3
  import type { SettingsTabItem } from "../settings/SettingsTabsPage.js";
4
4
  import type { AgentPageTabProps } from "./types.js";
5
5
  export declare const AGENT_RESOURCE_DOCS_HREF: Record<ResourceView, string>;
6
- export declare function ConnectionsTab({ canManageOrg, }?: Partial<AgentPageTabProps>): import("react").JSX.Element;
6
+ export declare function ConnectionsTab({ canManageOrg, onOAuthStart, oauthReturnPath, }?: Partial<AgentPageTabProps> & {
7
+ onOAuthStart?: (url: string) => void | Promise<void>;
8
+ oauthReturnPath?: string;
9
+ }): import("react").JSX.Element;
7
10
  export declare const AGENT_ACCESS_DOCS_HREF: {
8
11
  readonly mcp: string;
9
12
  readonly a2a: string;
@@ -117,7 +117,7 @@ function ServerStatus({ server }) {
117
117
  }
118
118
  return (_jsx("span", { className: "text-[11px] text-muted-foreground", children: "Status unknown" }));
119
119
  }
120
- export function ConnectionsTab({ canManageOrg, } = {}) {
120
+ export function ConnectionsTab({ canManageOrg, onOAuthStart, oauthReturnPath, } = {}) {
121
121
  const t = useT();
122
122
  const serversQuery = useMcpServers();
123
123
  const createServer = useCreateMcpServer();
@@ -181,7 +181,7 @@ export function ConnectionsTab({ canManageOrg, } = {}) {
181
181
  ? "No personal agent integrations yet"
182
182
  : "No workspace-shared agent integrations yet", description: section.scope === "user"
183
183
  ? "Connect a service to give the agent access to it."
184
- : "Agent integrations shared with this workspace will appear here." }))] }, section.scope))) })), _jsx(McpIntegrationDialog, { open: dialogOpen, onOpenChange: setDialogOpen, defaultScope: "user", canCreateOrgMcp: canCreateOrgMcp, hasOrg: hasOrg, onCreateMcpServer: onCreateMcpServer })] }) }));
184
+ : "Agent integrations shared with this workspace will appear here." }))] }, section.scope))) })), _jsx(McpIntegrationDialog, { open: dialogOpen, onOpenChange: setDialogOpen, defaultScope: "user", canCreateOrgMcp: canCreateOrgMcp, hasOrg: hasOrg, onCreateMcpServer: onCreateMcpServer, onOAuthStart: onOAuthStart, oauthReturnPath: oauthReturnPath })] }) }));
185
185
  }
186
186
  export const AGENT_ACCESS_DOCS_HREF = {
187
187
  mcp: docsUrl("mcp-protocol"),
@@ -3,9 +3,12 @@ export interface IntegrationConnectionChoiceProps {
3
3
  name: string;
4
4
  logo?: ReactNode;
5
5
  showWorkspaceOption: boolean;
6
+ workspaceOptionDisabled?: boolean;
7
+ workspaceOptionDisabledReason?: string;
8
+ personalOnlyReason?: string;
6
9
  busy?: boolean;
7
10
  onPersonal: () => void;
8
11
  onWorkspace: () => void;
9
12
  }
10
13
  /** The one small decision before an integration's advanced setup surface. */
11
- export declare function IntegrationConnectionChoice({ name, logo, showWorkspaceOption, busy, onPersonal, onWorkspace, }: IntegrationConnectionChoiceProps): import("react").JSX.Element;
14
+ export declare function IntegrationConnectionChoice({ name, logo, showWorkspaceOption, workspaceOptionDisabled, workspaceOptionDisabledReason, personalOnlyReason, busy, onPersonal, onWorkspace, }: IntegrationConnectionChoiceProps): import("react").JSX.Element;
@@ -1,6 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { IconLoader2, IconUser, IconUsersGroup } from "@tabler/icons-react";
3
+ import { useT } from "../i18n.js";
3
4
  /** The one small decision before an integration's advanced setup surface. */
4
- export function IntegrationConnectionChoice({ name, logo, showWorkspaceOption, busy = false, onPersonal, onWorkspace, }) {
5
- return (_jsxs("div", { className: "flex min-h-full flex-1 flex-col bg-background", children: [_jsx("header", { className: "flex min-h-16 items-center border-b border-border px-6 sm:px-10", children: _jsxs("div", { className: "flex min-w-0 items-center gap-3", children: [logo ? (_jsx("span", { className: "flex size-8 shrink-0 items-center justify-center rounded-md bg-muted/50 text-foreground", children: logo })) : null, _jsxs("span", { className: "truncate text-sm font-medium text-foreground", children: ["Connect ", name] })] }) }), _jsx("main", { className: "flex flex-1 justify-center overflow-y-auto px-6 py-12 sm:px-10 sm:py-[12vh]", children: _jsxs("div", { className: "w-full max-w-[420px] self-start", children: [_jsx("h1", { className: "text-2xl font-semibold tracking-[-0.03em] text-foreground sm:text-[28px]", children: "Who should use this?" }), _jsx("p", { className: "mt-2 text-sm leading-6 text-muted-foreground", children: "Choose where this connection is available." }), _jsxs("div", { className: "mt-8 grid gap-2.5", children: [_jsxs("button", { type: "button", onClick: onPersonal, disabled: busy, "aria-busy": busy, className: "flex min-h-12 items-center gap-3 rounded-lg bg-primary px-4 py-3 text-left text-primary-foreground transition-[background-color,opacity] hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-wait disabled:opacity-60", children: [_jsx(IconUser, { className: "size-4 shrink-0 opacity-75" }), _jsx("span", { className: "min-w-0 flex-1 text-sm font-medium", children: "Connect for me" }), busy ? (_jsx(IconLoader2, { className: "size-4 shrink-0 animate-spin" })) : null] }), showWorkspaceOption ? (_jsxs("button", { type: "button", onClick: onWorkspace, disabled: busy, className: "flex min-h-12 items-center gap-3 rounded-lg bg-muted/50 px-4 py-3 text-left text-foreground transition-colors hover:bg-muted/70 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-wait disabled:opacity-60", children: [_jsx(IconUsersGroup, { className: "size-4 shrink-0 text-muted-foreground" }), _jsx("span", { className: "min-w-0 flex-1 text-sm font-medium", children: "Set up for workspace" })] })) : null] })] }) })] }));
5
+ export function IntegrationConnectionChoice({ name, logo, showWorkspaceOption, workspaceOptionDisabled = false, workspaceOptionDisabledReason, personalOnlyReason, busy = false, onPersonal, onWorkspace, }) {
6
+ const t = useT();
7
+ return (_jsxs("div", { className: "flex min-h-full flex-1 flex-col bg-background", children: [_jsx("header", { className: "flex min-h-16 items-center border-b border-border px-6 sm:px-10", children: _jsxs("div", { className: "flex min-w-0 items-center gap-3", children: [logo ? (_jsx("span", { className: "flex size-8 shrink-0 items-center justify-center rounded-md bg-muted/50 text-foreground", children: logo })) : null, _jsxs("span", { className: "truncate text-sm font-medium text-foreground", children: [t("mcpIntegrations.connect"), " ", name] })] }) }), _jsx("main", { className: "flex flex-1 justify-center overflow-y-auto px-6 py-12 sm:px-10 sm:py-[12vh]", children: _jsxs("div", { className: "w-full max-w-[420px] self-start", children: [_jsx("h1", { className: "text-2xl font-semibold tracking-[-0.03em] text-foreground sm:text-[28px]", children: t("mcpIntegrations.scopeChoiceTitle") }), _jsx("p", { className: "mt-2 text-sm leading-6 text-muted-foreground", children: t("mcpIntegrations.scopeChoiceDescription") }), _jsxs("div", { className: "mt-8 grid gap-2.5", children: [_jsxs("button", { type: "button", onClick: onPersonal, disabled: busy, "aria-busy": busy, className: "flex min-h-12 items-center gap-3 rounded-lg bg-primary px-4 py-3 text-left text-primary-foreground transition-[background-color,opacity] hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-wait disabled:opacity-60", children: [_jsx(IconUser, { className: "size-4 shrink-0 opacity-75" }), _jsx("span", { className: "min-w-0 flex-1 text-sm font-medium", children: t("mcpIntegrations.connectForMe") }), busy ? (_jsx(IconLoader2, { className: "size-4 shrink-0 animate-spin" })) : null] }), showWorkspaceOption ? (_jsxs("button", { type: "button", onClick: onWorkspace, disabled: busy || workspaceOptionDisabled, "aria-describedby": workspaceOptionDisabledReason
8
+ ? "integration-workspace-scope-restriction"
9
+ : undefined, className: "flex min-h-12 items-center gap-3 rounded-lg bg-muted/50 px-4 py-3 text-left text-foreground transition-colors hover:bg-muted/70 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-60", children: [_jsx(IconUsersGroup, { className: "size-4 shrink-0 text-muted-foreground" }), _jsx("span", { className: "min-w-0 flex-1 text-sm font-medium", children: t("mcpIntegrations.setUpForWorkspace") }), workspaceOptionDisabledReason ? (_jsx("span", { id: "integration-workspace-scope-restriction", className: "shrink-0 text-[11px] font-normal text-muted-foreground", children: workspaceOptionDisabledReason })) : null] })) : null] }), personalOnlyReason ? (_jsx("p", { className: "mt-3 text-[11px] leading-relaxed text-muted-foreground", children: personalOnlyReason })) : null] }) })] }));
6
10
  }
@@ -6,10 +6,10 @@ import { docsUrl } from "../../shared/docs-url.js";
6
6
  import { appPath } from "../api-path.js";
7
7
  import { Tooltip, TooltipContent, TooltipTrigger, } from "../components/ui/tooltip.js";
8
8
  import { IntegrationGrid } from "../integrations/IntegrationGrid.js";
9
- import { buildMcpOAuthStartUrl, filterMcpIntegrations, getDefaultMcpIntegrations, navigateToMcpOAuthStart, shouldOfferMcpIntegrationOrganizationScope, } from "../resources/mcp-integration-catalog.js";
9
+ import { buildMcpOAuthStartUrl, filterMcpIntegrations, getDefaultMcpIntegrations, navigateToMcpOAuthStart, } from "../resources/mcp-integration-catalog.js";
10
10
  import { McpIntegrationDialog } from "../resources/McpIntegrationDialog.js";
11
11
  import { McpIntegrationLogo } from "../resources/McpIntegrationLogo.js";
12
- import { formatMcpServerError, useCreateMcpServer, useMcpServers, } from "../resources/use-mcp-servers.js";
12
+ import { formatMcpServerError, formatMcpServersLoadError, useCreateMcpServer, useMcpServers, } from "../resources/use-mcp-servers.js";
13
13
  import { useBuilderConnectFlow } from "../settings/useBuilderStatus.js";
14
14
  import { cn } from "../utils.js";
15
15
  import { shouldSkipFirstRunIntegrations } from "./first-run-enabled.js";
@@ -122,7 +122,9 @@ export function FirstRunOnboarding({ skipIntegrations = shouldSkipFirstRunIntegr
122
122
  connectingIntegrationId === integration.id) {
123
123
  return;
124
124
  }
125
- if (shouldOfferMcpIntegrationOrganizationScope(integration, hasOrg, canCreateOrgMcp)) {
125
+ if (!mcpServersQuery.isSuccess)
126
+ return;
127
+ if (hasOrg) {
126
128
  setIntegrationDialogId(integration.id);
127
129
  return;
128
130
  }
@@ -190,7 +192,7 @@ export function FirstRunOnboarding({ skipIntegrations = shouldSkipFirstRunIntegr
190
192
  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 bg-muted/35 p-4", children: [_jsx(CapabilityList, { capabilities: profile.capabilities }), _jsxs("div", { className: "mt-5 flex flex-col-reverse gap-2 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(skipIntegrations ? "ready" : "tools"), children: skipIntegrations ? "Continue" : "Continue to tools" })] })] })] }) }));
191
193
  }
192
194
  if (screen === "tools") {
193
- 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", { children: [_jsx("h1", { className: "text-2xl font-semibold tracking-[-0.05em] sm:text-3xl", children: "This app is an agent." }), _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 and take action. You can add more later in Settings." })] }), _jsxs("div", { className: "flex flex-col gap-4", children: [_jsxs("div", { className: "flex flex-col gap-3 pb-4", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx("div", { children: _jsx("p", { className: "text-sm font-medium text-foreground", children: "Agent integrations" }) }), _jsxs("label", { className: "relative w-full max-w-xs", 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(IntegrationGrid, { items: mcpIntegrations.map((integration) => {
195
+ 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", { children: [_jsx("h1", { className: "text-2xl font-semibold tracking-[-0.05em] sm:text-3xl", children: "This app is an agent." }), _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 and take action. You can add more later in Settings." })] }), _jsxs("div", { className: "flex flex-col gap-4", children: [_jsxs("div", { className: "flex flex-col gap-3 pb-4", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx("div", { children: _jsx("p", { className: "text-sm font-medium text-foreground", children: "Agent integrations" }) }), _jsxs("label", { className: "relative w-full max-w-xs", 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 })), mcpServersQuery.isError ? (_jsxs("div", { role: "alert", className: "rounded-md border border-destructive/20 bg-destructive/5 px-3 py-2 text-xs text-destructive", children: [_jsx("p", { children: formatMcpServersLoadError(mcpServersQuery.error) }), _jsx("button", { type: "button", onClick: () => void mcpServersQuery.refetch(), disabled: mcpServersQuery.isFetching, className: "mt-2 font-medium underline underline-offset-2 hover:text-foreground disabled:cursor-wait disabled:opacity-60", children: mcpServersQuery.isFetching ? "Retrying…" : "Retry" })] })) : null] }), _jsx(IntegrationGrid, { items: mcpIntegrations.map((integration) => {
194
196
  const connected = connectedUrls.has(compareUrl(integration.url));
195
197
  return {
196
198
  id: integration.id,
@@ -200,7 +202,9 @@ export function FirstRunOnboarding({ skipIntegrations = shouldSkipFirstRunIntegr
200
202
  status: connected ? "Connected" : undefined,
201
203
  statusClassName: "text-emerald-600 dark:text-emerald-400",
202
204
  actionLabel: connected ? "Connected" : "Connect",
203
- disabled: connected || connectingIntegrationId === integration.id,
205
+ disabled: connected ||
206
+ connectingIntegrationId === integration.id ||
207
+ !mcpServersQuery.isSuccess,
204
208
  onAction: () => void connectIntegration(integration),
205
209
  };
206
210
  }), emptyLabel: "No integrations match." })] })] }), integrationDialogId && (_jsx(McpIntegrationDialog, { open: true, onOpenChange: (open) => {
@@ -10,7 +10,9 @@ export interface McpIntegrationDialogProps {
10
10
  canCreateOrgMcp: boolean;
11
11
  hasOrg: boolean;
12
12
  onCreateMcpServer: (args: CreateMcpServerArgs) => Promise<unknown>;
13
+ onOAuthStart?: (url: string) => void | Promise<void>;
14
+ oauthReturnPath?: string;
13
15
  onCreated?: () => void;
14
16
  integrations?: DefaultMcpIntegration[];
15
17
  }
16
- export declare function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId, connectIntegrationId, quickConnectIntegrationId, defaultScope, canCreateOrgMcp, hasOrg, onCreateMcpServer, onCreated, integrations, }: McpIntegrationDialogProps): import("react").JSX.Element | null;
18
+ export declare function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId, connectIntegrationId, quickConnectIntegrationId, defaultScope, canCreateOrgMcp, hasOrg, onCreateMcpServer, onOAuthStart, oauthReturnPath, onCreated, integrations, }: McpIntegrationDialogProps): import("react").JSX.Element | null;
@@ -8,9 +8,9 @@ import { useT } from "../i18n.js";
8
8
  import { IntegrationConnectionChoice } from "../integrations/IntegrationConnectionChoice.js";
9
9
  import { IntegrationGrid } from "../integrations/IntegrationGrid.js";
10
10
  import { cn } from "../utils.js";
11
- import { buildMcpOAuthStartUrl, createMcpIntegrationFormDefaults, filterMcpIntegrations, getMcpIntegrationApiFallback, getDefaultMcpIntegrations, isCustomMcpIntegrationEnabled, navigateToMcpOAuthStart, resolveMcpIntegrationScope, shouldOfferMcpIntegrationOrganizationScope, shouldOfferMcpOrganizationScope, } from "./mcp-integration-catalog.js";
11
+ import { buildMcpOAuthStartUrl, createMcpIntegrationFormDefaults, filterMcpIntegrations, getMcpIntegrationApiFallback, getDefaultMcpIntegrations, isCustomMcpIntegrationEnabled, navigateToMcpOAuthStart, resolveMcpIntegrationScope, shouldOfferMcpIntegrationOrganizationScope, shouldOfferMcpOrganizationScope, supportsMcpIntegrationOrganizationScope, } from "./mcp-integration-catalog.js";
12
12
  import { McpIntegrationLogo } from "./McpIntegrationLogo.js";
13
- import { formatMcpServerError, getMcpUrlValidationError, useMcpServersApi, useMcpServers, } from "./use-mcp-servers.js";
13
+ import { formatMcpServerError, formatMcpServersLoadError, getMcpUrlValidationError, useMcpServersApi, useMcpServers, } from "./use-mcp-servers.js";
14
14
  function parseHeaderLines(text) {
15
15
  const out = {};
16
16
  for (const line of text.split(/\r?\n/)) {
@@ -49,7 +49,7 @@ function resolveIntegrationScope(integration, defaultScope, hasOrg, canCreateOrg
49
49
  (integration.supportsOrganizationScope === true &&
50
50
  integration.managedOAuth !== true));
51
51
  }
52
- export function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId = null, connectIntegrationId = null, quickConnectIntegrationId = null, defaultScope, canCreateOrgMcp, hasOrg, onCreateMcpServer, onCreated, integrations, }) {
52
+ export function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId = null, connectIntegrationId = null, quickConnectIntegrationId = null, defaultScope, canCreateOrgMcp, hasOrg, onCreateMcpServer, onOAuthStart, oauthReturnPath, onCreated, integrations, }) {
53
53
  const t = useT();
54
54
  const [mode, setMode] = useState("catalog");
55
55
  const [query, setQuery] = useState("");
@@ -89,11 +89,21 @@ export function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId
89
89
  useEffect(() => {
90
90
  if (!open)
91
91
  return;
92
+ if (initialIntegrationId && !mcpServersQuery.isSuccess)
93
+ return;
92
94
  const initialIntegration = initialIntegrationId
93
95
  ? defaultIntegrations.find((integration) => integration.id === initialIntegrationId)
94
96
  : null;
95
97
  const initialDefaults = createMcpIntegrationFormDefaults(initialIntegration);
96
- setMode(initialIntegration || !showCatalog ? "form" : "catalog");
98
+ const initialNeedsScopeChoice = Boolean(initialIntegration &&
99
+ hasOrg &&
100
+ requiresMcpIntegrationSetup(initialIntegration) &&
101
+ supportsMcpIntegrationOrganizationScope(initialIntegration));
102
+ setMode(initialNeedsScopeChoice
103
+ ? "choice"
104
+ : initialIntegration || !showCatalog
105
+ ? "form"
106
+ : "catalog");
97
107
  setQuery("");
98
108
  setSelected(initialIntegration ?? null);
99
109
  setScope(resolveIntegrationScope(initialIntegration, defaultScope, hasOrg, canCreateOrgMcp));
@@ -114,6 +124,7 @@ export function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId
114
124
  open,
115
125
  safeDefaultScope,
116
126
  showCatalog,
127
+ mcpServersQuery.isSuccess,
117
128
  ]);
118
129
  useEffect(() => {
119
130
  if (open && mode === "form") {
@@ -147,18 +158,31 @@ export function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId
147
158
  return;
148
159
  }
149
160
  setBusy(true);
150
- const returnUrl = typeof window === "undefined"
151
- ? "/"
152
- : window.location.pathname +
153
- window.location.search +
154
- window.location.hash;
155
- navigateToMcpOAuthStart(agentNativePath(buildMcpOAuthStartUrl({
161
+ const returnUrl = oauthReturnPath?.startsWith("/")
162
+ ? oauthReturnPath
163
+ : typeof window === "undefined"
164
+ ? "/"
165
+ : window.location.pathname +
166
+ window.location.search +
167
+ window.location.hash;
168
+ const oauthUrl = agentNativePath(buildMcpOAuthStartUrl({
156
169
  name: args.name,
157
170
  url: args.url,
158
171
  description: args.description,
159
172
  scope: options?.scope ?? scope,
160
173
  returnUrl,
161
- })));
174
+ }));
175
+ if (!onOAuthStart) {
176
+ navigateToMcpOAuthStart(oauthUrl);
177
+ return;
178
+ }
179
+ void Promise.resolve()
180
+ .then(() => onOAuthStart(oauthUrl))
181
+ .then(() => onOpenChange(false))
182
+ .catch((cause) => {
183
+ setBusy(false);
184
+ setError(formatMcpServerError(cause));
185
+ });
162
186
  };
163
187
  const connectWithOAuth = (integration, options) => beginOAuth({
164
188
  name: integration.name,
@@ -218,6 +242,11 @@ export function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId
218
242
  });
219
243
  };
220
244
  const quickConnect = (integration) => {
245
+ if (hasOrg) {
246
+ setSelected(integration);
247
+ setMode("choice");
248
+ return;
249
+ }
221
250
  if (requiresMcpIntegrationSetup(integration)) {
222
251
  openForm(integration);
223
252
  return;
@@ -240,6 +269,13 @@ export function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId
240
269
  });
241
270
  };
242
271
  const selectCatalogConnection = (integration) => {
272
+ if (!mcpServersQuery.isSuccess)
273
+ return;
274
+ if (hasOrg) {
275
+ setSelected(integration);
276
+ setMode("choice");
277
+ return;
278
+ }
243
279
  if (requiresMcpIntegrationSetup(integration)) {
244
280
  const apiFallback = getMcpIntegrationApiFallback(integration);
245
281
  if (apiFallback) {
@@ -250,11 +286,6 @@ export function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId
250
286
  }
251
287
  return;
252
288
  }
253
- if (shouldOfferMcpIntegrationOrganizationScope(integration, hasOrg, canCreateOrgMcp)) {
254
- setSelected(integration);
255
- setMode("choice");
256
- return;
257
- }
258
289
  quickConnect(integration);
259
290
  };
260
291
  quickConnectRef.current = quickConnect;
@@ -267,15 +298,30 @@ export function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId
267
298
  quickConnectAttemptedRef.current === quickConnectIntegrationId) {
268
299
  return;
269
300
  }
301
+ if (mcpServersQuery.isError)
302
+ return;
303
+ if (!mcpServersQuery.isSuccess)
304
+ return;
270
305
  const integration = defaultIntegrations.find((candidate) => candidate.id === quickConnectIntegrationId);
271
306
  if (!integration)
272
307
  return;
273
308
  quickConnectAttemptedRef.current = quickConnectIntegrationId;
274
309
  quickConnectRef.current?.(integration);
275
- }, [defaultIntegrations, open, quickConnectIntegrationId]);
310
+ }, [
311
+ defaultIntegrations,
312
+ hasOrg,
313
+ mcpServersQuery.isError,
314
+ mcpServersQuery.isSuccess,
315
+ open,
316
+ quickConnectIntegrationId,
317
+ ]);
276
318
  useEffect(() => {
277
319
  if (!open || !connectIntegrationId)
278
320
  return;
321
+ if (mcpServersQuery.isError)
322
+ return;
323
+ if (!mcpServersQuery.isSuccess)
324
+ return;
279
325
  const integration = defaultIntegrations.find((candidate) => candidate.id === connectIntegrationId);
280
326
  if (!integration)
281
327
  return;
@@ -283,25 +329,36 @@ export function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId
283
329
  if (quickConnectAttemptedRef.current === attemptKey)
284
330
  return;
285
331
  quickConnectAttemptedRef.current = attemptKey;
332
+ if (hasOrg) {
333
+ setSelected(integration);
334
+ setMode("choice");
335
+ return;
336
+ }
286
337
  if (requiresMcpIntegrationSetup(integration)) {
287
338
  openForm(integration);
288
339
  return;
289
340
  }
290
- const showWorkspaceChoice = shouldOfferMcpIntegrationOrganizationScope(integration, hasOrg, canCreateOrgMcp);
291
- if (!showWorkspaceChoice) {
292
- quickConnectRef.current?.(integration);
293
- }
294
- else {
295
- setMode("choice");
296
- }
341
+ quickConnectRef.current?.(integration);
297
342
  }, [
298
343
  canCreateOrgMcp,
299
344
  connectIntegrationId,
300
345
  defaultIntegrations,
301
346
  hasOrg,
347
+ mcpServersQuery.isError,
348
+ mcpServersQuery.isSuccess,
302
349
  open,
303
350
  ]);
304
351
  const connectPersonal = (integration) => {
352
+ if (requiresMcpIntegrationSetup(integration)) {
353
+ const apiFallback = getMcpIntegrationApiFallback(integration);
354
+ if (apiFallback) {
355
+ openAgentSettings(`secrets:${apiFallback.secretKey}`);
356
+ }
357
+ else {
358
+ openForm(integration, { scope: "user" });
359
+ }
360
+ return;
361
+ }
305
362
  if (integration.authMode === "oauth") {
306
363
  connectWithOAuth(integration, { scope: "user" });
307
364
  return;
@@ -319,6 +376,12 @@ export function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId
319
376
  openForm(integration, { scope: "user" });
320
377
  };
321
378
  const connectWorkspace = (integration) => {
379
+ if (!canCreateOrgMcp)
380
+ return;
381
+ if (requiresMcpIntegrationSetup(integration)) {
382
+ openForm(integration, { scope: "org" });
383
+ return;
384
+ }
322
385
  if (integration.authMode === "oauth") {
323
386
  connectWithOAuth(integration, { scope: "org" });
324
387
  return;
@@ -384,93 +447,99 @@ export function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId
384
447
  };
385
448
  if (!showCatalog && !customIntegrationEnabled)
386
449
  return null;
387
- return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsx(DialogContent, { "aria-describedby": undefined, className: "inset-0 flex h-[100dvh] max-h-none w-full max-w-none translate-x-0 translate-y-0 flex-col gap-0 overflow-hidden rounded-none p-0", children: mode === "choice" && selected ? (_jsxs(_Fragment, { children: [_jsx(DialogHeader, { className: "sr-only", children: _jsxs(DialogTitle, { children: ["Connect ", selected.name] }) }), _jsx(IntegrationConnectionChoice, { name: selected.name, logo: _jsx(McpIntegrationLogo, { name: selected.name, logoUrl: selected.logoUrl, integrationId: selected.id, className: "size-7 rounded-md", imageClassName: "size-full p-1" }), showWorkspaceOption: shouldOfferMcpIntegrationOrganizationScope(selected, hasOrg, canCreateOrgMcp), busy: busy, onPersonal: () => connectPersonal(selected), onWorkspace: () => connectWorkspace(selected) })] })) : mode === "catalog" ? (_jsxs(_Fragment, { children: [_jsxs(DialogHeader, { className: "shrink-0 border-b border-border px-7 pb-5 pe-14 pt-7 sm:px-10", children: [_jsx(DialogTitle, { children: t("mcpIntegrations.title") }), _jsx(DialogDescription, { children: t("mcpIntegrations.description", {
388
- count: defaultIntegrations.length,
389
- }) })] }), _jsx("div", { className: "shrink-0 px-7 pb-5 sm:px-10", children: _jsxs("div", { className: "mx-auto flex w-full max-w-5xl flex-col gap-3 sm:flex-row", children: [_jsxs("label", { className: "relative min-w-0 flex-1", 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: query, onChange: (event) => setQuery(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: t("mcpIntegrations.searchPlaceholder") })] }), _jsx("button", { type: "button", onClick: () => openForm(null), className: cn("inline-flex h-9 items-center justify-center gap-1.5 rounded-md border border-border bg-background px-3 text-[12px] font-medium text-foreground hover:bg-accent", !customIntegrationEnabled && "hidden"), children: t("mcpIntegrations.addYourOwn") })] }) }), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto px-7 pb-10 pt-7 sm:px-10", children: _jsxs("div", { className: "mx-auto w-full max-w-5xl", children: [error && (_jsx("div", { className: "mb-3 rounded-md border border-destructive/20 bg-destructive/5 px-3 py-2 text-[12px] leading-relaxed text-destructive", children: error })), _jsx(IntegrationGrid, { items: filteredIntegrations.map((integration) => {
390
- const connected = connectedUrls.has(compareUrl(integration.url));
391
- const setupOnly = requiresMcpIntegrationSetup(integration);
392
- const apiFallback = getMcpIntegrationApiFallback(integration);
393
- return {
394
- id: integration.id,
395
- name: integration.name,
396
- description: t(integration.descriptionKey),
397
- logo: (_jsx(McpIntegrationLogo, { name: integration.name, logoUrl: integration.logoUrl, integrationId: integration.id, className: "size-7 rounded-md", imageClassName: "size-full p-1" })),
398
- status: connected
399
- ? t("mcpIntegrations.connected")
400
- : setupOnly
401
- ? t("mcpIntegrations.status.setupRequired")
402
- : undefined,
403
- statusClassName: connected
404
- ? "text-emerald-600 dark:text-emerald-400"
405
- : "text-muted-foreground",
406
- actionLabel: connected
407
- ? "Manage"
408
- : setupOnly && apiFallback
409
- ? t("mcpIntegrations.useApiToken")
450
+ return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { "aria-describedby": undefined, className: "inset-0 flex h-[100dvh] max-h-none w-full max-w-none translate-x-0 translate-y-0 flex-col gap-0 overflow-hidden rounded-none p-0", children: [mcpServersQuery.isError ? (_jsxs("div", { role: "alert", className: "mx-7 mt-4 shrink-0 rounded-md border border-destructive/20 bg-destructive/5 px-3 py-2 text-xs text-destructive sm:mx-10", children: [_jsx("p", { children: formatMcpServersLoadError(mcpServersQuery.error) }), _jsx("button", { type: "button", onClick: () => void mcpServersQuery.refetch(), disabled: mcpServersQuery.isFetching, className: "mt-2 font-medium underline underline-offset-2 hover:text-foreground disabled:cursor-wait disabled:opacity-60", children: mcpServersQuery.isFetching
451
+ ? t("mcpIntegrations.retrying")
452
+ : t("mcpIntegrations.retry") })] })) : null, mode === "choice" && selected ? (_jsxs(_Fragment, { children: [_jsx(DialogHeader, { className: "sr-only", children: _jsxs(DialogTitle, { children: [t("mcpIntegrations.connect"), " ", selected.name] }) }), _jsx(IntegrationConnectionChoice, { name: selected.name, logo: _jsx(McpIntegrationLogo, { name: selected.name, logoUrl: selected.logoUrl, integrationId: selected.id, className: "size-7 rounded-md", imageClassName: "size-full p-1" }), showWorkspaceOption: supportsMcpIntegrationOrganizationScope(selected), workspaceOptionDisabled: !canCreateOrgMcp, workspaceOptionDisabledReason: !canCreateOrgMcp
453
+ ? t("mcpIntegrations.workspaceAdminRequired")
454
+ : undefined, personalOnlyReason: !supportsMcpIntegrationOrganizationScope(selected)
455
+ ? t("mcpIntegrations.personalOnlyDescription")
456
+ : undefined, busy: busy, onPersonal: () => connectPersonal(selected), onWorkspace: () => connectWorkspace(selected) })] })) : mode === "catalog" ? (_jsxs(_Fragment, { children: [_jsxs(DialogHeader, { className: "shrink-0 border-b border-border px-7 pb-5 pe-14 pt-7 sm:px-10", children: [_jsx(DialogTitle, { children: t("mcpIntegrations.title") }), _jsx(DialogDescription, { children: t("mcpIntegrations.description", {
457
+ count: defaultIntegrations.length,
458
+ }) })] }), _jsx("div", { className: "shrink-0 px-7 pb-5 sm:px-10", children: _jsxs("div", { className: "mx-auto flex w-full max-w-5xl flex-col gap-3 sm:flex-row", children: [_jsxs("label", { className: "relative min-w-0 flex-1", 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: query, onChange: (event) => setQuery(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: t("mcpIntegrations.searchPlaceholder") })] }), _jsx("button", { type: "button", onClick: () => openForm(null), className: cn("inline-flex h-9 items-center justify-center gap-1.5 rounded-md border border-border bg-background px-3 text-[12px] font-medium text-foreground hover:bg-accent", !customIntegrationEnabled && "hidden"), children: t("mcpIntegrations.addYourOwn") })] }) }), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto px-7 pb-10 pt-7 sm:px-10", children: _jsxs("div", { className: "mx-auto w-full max-w-5xl", children: [error && (_jsx("div", { className: "mb-3 rounded-md border border-destructive/20 bg-destructive/5 px-3 py-2 text-[12px] leading-relaxed text-destructive", children: error })), !mcpServersQuery.isSuccess && !mcpServersQuery.isError ? (_jsx("div", { role: "status", className: "mb-3 rounded-md border border-border bg-muted/30 px-3 py-2 text-[12px] leading-relaxed text-muted-foreground", children: t("mcpIntegrations.loadingScopeMetadata") })) : null, _jsx(IntegrationGrid, { items: filteredIntegrations.map((integration) => {
459
+ const connected = connectedUrls.has(compareUrl(integration.url));
460
+ const setupOnly = requiresMcpIntegrationSetup(integration);
461
+ const apiFallback = getMcpIntegrationApiFallback(integration);
462
+ return {
463
+ id: integration.id,
464
+ name: integration.name,
465
+ description: t(integration.descriptionKey),
466
+ logo: (_jsx(McpIntegrationLogo, { name: integration.name, logoUrl: integration.logoUrl, integrationId: integration.id, className: "size-7 rounded-md", imageClassName: "size-full p-1" })),
467
+ status: connected
468
+ ? t("mcpIntegrations.connected")
410
469
  : setupOnly
411
- ? t("mcpIntegrations.viewSetup")
412
- : t("mcpIntegrations.connect"),
413
- disabled: connected || busy,
414
- onAction: () => {
415
- if (connected) {
416
- openForm(integration);
417
- return;
418
- }
419
- selectCatalogConnection(integration);
420
- },
421
- };
422
- }), emptyLabel: t("mcpIntegrations.noMatches") })] }) })] })) : (_jsxs(_Fragment, { children: [_jsxs(DialogHeader, { className: "shrink-0 border-b border-border px-7 pb-5 pe-14 pt-7 sm:px-10", children: [_jsxs("button", { type: "button", onClick: () => {
423
- clearFeedback();
424
- setMode("catalog");
425
- }, className: cn("mb-1 inline-flex w-fit items-center gap-1 text-[11px] text-muted-foreground hover:text-foreground", !showCatalog && "hidden"), children: [_jsx(IconArrowLeft, { className: "h-3 w-3 rtl:-scale-x-100" }), t("mcpIntegrations.backToIntegrations")] }), _jsx(DialogTitle, { children: selected
426
- ? selectedRequiresSetup
427
- ? t("mcpIntegrations.setupTitle", {
428
- name: selected.name,
429
- })
430
- : t("mcpIntegrations.configureTitle", {
431
- name: selected.name,
432
- })
433
- : t("mcpIntegrations.customTitle") }), _jsx(DialogDescription, { children: selected
434
- ? selectedRequiresSetup
435
- ? t("mcpIntegrations.providerSetupFormDescription")
436
- : selected.authMode === "none"
437
- ? t("mcpIntegrations.presetNoAuthDescription")
438
- : t("mcpIntegrations.presetAuthDescription")
439
- : t("mcpIntegrations.customDescription") })] }), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto px-7 py-7 sm:px-10", children: _jsxs("div", { className: "mx-auto max-w-2xl space-y-3", children: [renderScopeSelector(), selected?.setupNoteKey && !selectedRequiresSetup ? (_jsx("div", { className: "rounded-md bg-muted/40 px-3 py-2 text-[11px] leading-relaxed text-muted-foreground", children: t(selected.setupNoteKey) })) : null, selectedRequiresSetup && selected && (_jsxs("div", { className: "mx-auto grid w-full max-w-xl gap-4 py-8", children: [_jsxs("div", { children: [_jsx("p", { className: "text-base font-semibold tracking-[-0.02em] text-foreground", children: t("mcpIntegrations.providerSetupRequired") }), _jsx("p", { className: "mt-1 text-sm leading-6 text-muted-foreground", children: t("mcpIntegrations.providerSetupDescription", {
440
- name: selected.name,
441
- }) })] }), selected.setupNoteKey ? (_jsx("p", { className: "text-sm leading-6 text-muted-foreground", children: t(selected.setupNoteKey) })) : null, selected.docsUrl ? (_jsxs("a", { href: selected.docsUrl, target: "_blank", rel: "noopener noreferrer", className: "inline-flex w-fit items-center gap-1 text-sm font-medium text-foreground underline underline-offset-4 hover:text-muted-foreground", children: [t("mcpIntegrations.viewSetup"), _jsx(IconExternalLink, { className: "size-3.5" })] })) : null] })), !selected && (_jsxs("div", { className: "flex items-center justify-between gap-3 rounded-md bg-muted/30 px-3 py-2 text-[11px]", children: [_jsx("span", { className: "text-muted-foreground", children: customAuthMode === "oauth"
442
- ? t(
443
- /* i18n-key-ignore */
444
- "mcpIntegrations.customOAuthDefault", { defaultValue: "Sign in with OAuth" })
445
- : t(
446
- /* i18n-key-ignore */
447
- "mcpIntegrations.customHeadersMode", { defaultValue: "Use an API key" }) }), _jsx("button", { type: "button", onClick: () => {
448
- setCustomAuthMode((current) => current === "oauth" ? "headers" : "oauth");
449
- clearFeedback();
450
- }, className: "font-medium text-foreground underline underline-offset-2 hover:text-muted-foreground", children: customAuthMode === "oauth"
451
- ? t(
452
- /* i18n-key-ignore */
453
- "mcpIntegrations.useApiKeyInstead", { defaultValue: "Use an API key instead" })
454
- : t(
455
- /* i18n-key-ignore */
456
- "mcpIntegrations.useOAuthInstead", { defaultValue: "Use OAuth instead" }) })] })), !selectedRequiresSetup && (_jsxs(_Fragment, { children: [selected?.authMode === "oauth" && (_jsx("div", { className: "rounded-md border border-primary/20 bg-primary/5 px-3 py-2 text-[11px] leading-relaxed text-primary", children: t("mcpIntegrations.oauthNotice") })), _jsxs("label", { className: "block", children: [_jsx("span", { className: "mb-1 block text-[10px] font-medium text-muted-foreground", children: t("mcpIntegrations.serverName") }), _jsx("input", { ref: inputRef, value: name, onChange: (event) => {
457
- setName(event.target.value);
458
- clearFeedback();
459
- }, className: "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-ring", placeholder: t("mcpIntegrations.serverNamePlaceholder") })] }), _jsxs("label", { className: "block", children: [_jsx("span", { className: "mb-1 block text-[10px] font-medium text-muted-foreground", children: t("mcpIntegrations.url") }), _jsx("input", { value: url, onChange: (event) => {
460
- setUrl(event.target.value);
461
- clearFeedback();
462
- }, className: "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-ring", placeholder: t("mcpIntegrations.urlPlaceholder") })] }), _jsxs("label", { className: "block", children: [_jsx("span", { className: "mb-1 block text-[10px] font-medium text-muted-foreground", children: t("mcpIntegrations.fieldDescription") }), _jsx("input", { value: description, onChange: (event) => {
463
- setDescription(event.target.value);
464
- clearFeedback();
465
- }, className: "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-ring", placeholder: t("mcpIntegrations.descriptionPlaceholder") })] }), (selected
466
- ? selected.authMode !== "oauth"
467
- : customAuthMode === "headers") && (_jsxs("label", { className: "block", children: [_jsx("span", { className: "mb-1 block text-[10px] font-medium text-muted-foreground", children: t("mcpIntegrations.headers") }), _jsx("textarea", { value: headersText, onChange: (event) => {
468
- setHeadersText(event.target.value);
469
- clearFeedback();
470
- }, rows: 3, className: "w-full resize-y rounded-md border border-border bg-background px-2.5 py-1.5 text-[12px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-ring", style: {
471
- fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace',
472
- }, placeholder: selected?.headerPlaceholder ??
473
- t("mcpIntegrations.headersPlaceholder") })] })), selected?.docsUrl && (_jsxs("a", { href: selected.docsUrl, target: "_blank", rel: "noopener noreferrer", className: "inline-flex items-center gap-1 text-[11px] text-muted-foreground underline hover:text-foreground", children: [t("mcpIntegrations.openSetupDocs"), _jsx(IconExternalLink, { className: "h-3 w-3" })] }))] })), testResult && (_jsxs("div", { className: cn("flex items-start gap-1 rounded-md px-3 py-2 text-[11px] leading-snug", testResult.ok
474
- ? "bg-green-500/5 text-green-600 dark:text-green-400"
475
- : "bg-red-500/5 text-red-600 dark:text-red-400"), children: [testResult.ok && (_jsx(IconCheck, { className: "mt-0.5 h-3 w-3 shrink-0" })), _jsx("span", { className: "min-w-0 break-words", children: testResult.message })] })), error && (_jsx("div", { className: "break-words rounded-md bg-red-500/5 px-3 py-2 text-[11px] leading-snug text-red-600 dark:text-red-400", children: error }))] }) }), _jsxs("div", { className: "flex shrink-0 items-center justify-between gap-2 border-t border-border px-7 py-4", children: [!selectedRequiresSetup && (_jsx("button", { type: "button", onClick: runTest, disabled: !url.trim() || busy, className: "rounded-md border border-border bg-background px-3 py-1.5 text-[12px] font-medium text-foreground hover:bg-accent disabled:pointer-events-none disabled:opacity-40", children: t("mcpIntegrations.test") })), !selected && customAuthMode === "oauth" ? (_jsxs("button", { type: "button", onClick: connectCustomWithOAuth, disabled: !name.trim() || !url.trim() || busy, "aria-busy": busy, className: "rounded-md border border-border bg-background px-3 py-1.5 text-[12px] font-medium text-foreground hover:bg-accent disabled:pointer-events-none disabled:opacity-40", children: [busy && (_jsx(IconLoader2, { className: "me-1.5 inline h-3.5 w-3.5 animate-spin" })), t("mcpIntegrations.connectWithOAuth")] })) : null, selectedRequiresSetup ? (_jsxs("div", { className: "ms-auto flex items-center gap-2", children: [selected?.docsUrl ? (_jsxs("a", { href: selected.docsUrl, target: "_blank", rel: "noopener noreferrer", className: "inline-flex min-w-[92px] items-center justify-center gap-1.5 rounded-md border border-border bg-background px-3 py-1.5 text-[12px] font-medium text-foreground hover:bg-accent", children: [t("mcpIntegrations.viewSetup"), _jsx(IconExternalLink, { className: "h-3 w-3" })] })) : null, selected?.authMode === "oauth" && (_jsxs("button", { type: "button", onClick: () => connectWithOAuth(selected), disabled: busy, "aria-busy": busy, className: "inline-flex min-w-[132px] items-center justify-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-[12px] font-medium text-primary-foreground hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-40", children: [busy && (_jsx(IconLoader2, { className: "h-3.5 w-3.5 animate-spin" })), t("mcpIntegrations.continueToConnect")] }))] })) : selected?.authMode === "oauth" ? (_jsxs("button", { type: "button", onClick: () => connectWithOAuth(selected), disabled: !name.trim() || !url.trim() || busy, "aria-busy": busy, className: "inline-flex min-w-[92px] items-center justify-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-[12px] font-medium text-primary-foreground hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-40", children: [busy && _jsx(IconLoader2, { className: "h-3.5 w-3.5 animate-spin" }), t("mcpIntegrations.connectWithOAuth")] })) : !selected && customAuthMode === "oauth" ? null : (_jsxs("button", { type: "button", onClick: submitForm, disabled: !name.trim() || !url.trim() || busy, className: "inline-flex min-w-[92px] items-center justify-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-[12px] font-medium text-primary-foreground hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-40", children: [busy && _jsx(IconLoader2, { className: "h-3.5 w-3.5 animate-spin" }), t("mcpIntegrations.connect")] }))] })] })) }) }));
470
+ ? t("mcpIntegrations.status.setupRequired")
471
+ : undefined,
472
+ statusClassName: connected
473
+ ? "text-emerald-600 dark:text-emerald-400"
474
+ : "text-muted-foreground",
475
+ actionLabel: connected
476
+ ? "Manage"
477
+ : setupOnly && apiFallback
478
+ ? t("mcpIntegrations.useApiToken")
479
+ : setupOnly
480
+ ? t("mcpIntegrations.viewSetup")
481
+ : t("mcpIntegrations.connect"),
482
+ disabled: connected || busy || !mcpServersQuery.isSuccess,
483
+ onAction: () => {
484
+ if (connected) {
485
+ openForm(integration);
486
+ return;
487
+ }
488
+ selectCatalogConnection(integration);
489
+ },
490
+ };
491
+ }), emptyLabel: t("mcpIntegrations.noMatches") })] }) })] })) : (_jsxs(_Fragment, { children: [_jsxs(DialogHeader, { className: "shrink-0 border-b border-border px-7 pb-5 pe-14 pt-7 sm:px-10", children: [_jsxs("button", { type: "button", onClick: () => {
492
+ clearFeedback();
493
+ setMode("catalog");
494
+ }, className: cn("mb-1 inline-flex w-fit items-center gap-1 text-[11px] text-muted-foreground hover:text-foreground", !showCatalog && "hidden"), children: [_jsx(IconArrowLeft, { className: "h-3 w-3 rtl:-scale-x-100" }), t("mcpIntegrations.backToIntegrations")] }), _jsx(DialogTitle, { children: selected
495
+ ? selectedRequiresSetup
496
+ ? t("mcpIntegrations.setupTitle", {
497
+ name: selected.name,
498
+ })
499
+ : t("mcpIntegrations.configureTitle", {
500
+ name: selected.name,
501
+ })
502
+ : t("mcpIntegrations.customTitle") }), _jsx(DialogDescription, { children: selected
503
+ ? selectedRequiresSetup
504
+ ? t("mcpIntegrations.providerSetupFormDescription")
505
+ : selected.authMode === "none"
506
+ ? t("mcpIntegrations.presetNoAuthDescription")
507
+ : t("mcpIntegrations.presetAuthDescription")
508
+ : t("mcpIntegrations.customDescription") })] }), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto px-7 py-7 sm:px-10", children: _jsxs("div", { className: "mx-auto max-w-2xl space-y-3", children: [renderScopeSelector(), selected?.setupNoteKey && !selectedRequiresSetup ? (_jsx("div", { className: "rounded-md bg-muted/40 px-3 py-2 text-[11px] leading-relaxed text-muted-foreground", children: t(selected.setupNoteKey) })) : null, selectedRequiresSetup && selected && (_jsxs("div", { className: "mx-auto grid w-full max-w-xl gap-4 py-8", children: [_jsxs("div", { children: [_jsx("p", { className: "text-base font-semibold tracking-[-0.02em] text-foreground", children: t("mcpIntegrations.providerSetupRequired") }), _jsx("p", { className: "mt-1 text-sm leading-6 text-muted-foreground", children: t("mcpIntegrations.providerSetupDescription", {
509
+ name: selected.name,
510
+ }) })] }), selected.setupNoteKey ? (_jsx("p", { className: "text-sm leading-6 text-muted-foreground", children: t(selected.setupNoteKey) })) : null, selected.docsUrl ? (_jsxs("a", { href: selected.docsUrl, target: "_blank", rel: "noopener noreferrer", className: "inline-flex w-fit items-center gap-1 text-sm font-medium text-foreground underline underline-offset-4 hover:text-muted-foreground", children: [t("mcpIntegrations.viewSetup"), _jsx(IconExternalLink, { className: "size-3.5" })] })) : null] })), !selected && (_jsxs("div", { className: "flex items-center justify-between gap-3 rounded-md bg-muted/30 px-3 py-2 text-[11px]", children: [_jsx("span", { className: "text-muted-foreground", children: customAuthMode === "oauth"
511
+ ? t(
512
+ /* i18n-key-ignore */
513
+ "mcpIntegrations.customOAuthDefault", { defaultValue: "Sign in with OAuth" })
514
+ : t(
515
+ /* i18n-key-ignore */
516
+ "mcpIntegrations.customHeadersMode", { defaultValue: "Use an API key" }) }), _jsx("button", { type: "button", onClick: () => {
517
+ setCustomAuthMode((current) => current === "oauth" ? "headers" : "oauth");
518
+ clearFeedback();
519
+ }, className: "font-medium text-foreground underline underline-offset-2 hover:text-muted-foreground", children: customAuthMode === "oauth"
520
+ ? t(
521
+ /* i18n-key-ignore */
522
+ "mcpIntegrations.useApiKeyInstead", { defaultValue: "Use an API key instead" })
523
+ : t(
524
+ /* i18n-key-ignore */
525
+ "mcpIntegrations.useOAuthInstead", { defaultValue: "Use OAuth instead" }) })] })), !selectedRequiresSetup && (_jsxs(_Fragment, { children: [selected?.authMode === "oauth" && (_jsx("div", { className: "rounded-md border border-primary/20 bg-primary/5 px-3 py-2 text-[11px] leading-relaxed text-primary", children: t("mcpIntegrations.oauthNotice") })), _jsxs("label", { className: "block", children: [_jsx("span", { className: "mb-1 block text-[10px] font-medium text-muted-foreground", children: t("mcpIntegrations.serverName") }), _jsx("input", { ref: inputRef, value: name, onChange: (event) => {
526
+ setName(event.target.value);
527
+ clearFeedback();
528
+ }, className: "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-ring", placeholder: t("mcpIntegrations.serverNamePlaceholder") })] }), _jsxs("label", { className: "block", children: [_jsx("span", { className: "mb-1 block text-[10px] font-medium text-muted-foreground", children: t("mcpIntegrations.url") }), _jsx("input", { value: url, onChange: (event) => {
529
+ setUrl(event.target.value);
530
+ clearFeedback();
531
+ }, className: "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-ring", placeholder: t("mcpIntegrations.urlPlaceholder") })] }), _jsxs("label", { className: "block", children: [_jsx("span", { className: "mb-1 block text-[10px] font-medium text-muted-foreground", children: t("mcpIntegrations.fieldDescription") }), _jsx("input", { value: description, onChange: (event) => {
532
+ setDescription(event.target.value);
533
+ clearFeedback();
534
+ }, className: "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-ring", placeholder: t("mcpIntegrations.descriptionPlaceholder") })] }), (selected
535
+ ? selected.authMode !== "oauth"
536
+ : customAuthMode === "headers") && (_jsxs("label", { className: "block", children: [_jsx("span", { className: "mb-1 block text-[10px] font-medium text-muted-foreground", children: t("mcpIntegrations.headers") }), _jsx("textarea", { value: headersText, onChange: (event) => {
537
+ setHeadersText(event.target.value);
538
+ clearFeedback();
539
+ }, rows: 3, className: "w-full resize-y rounded-md border border-border bg-background px-2.5 py-1.5 text-[12px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-ring", style: {
540
+ fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace',
541
+ }, placeholder: selected?.headerPlaceholder ??
542
+ t("mcpIntegrations.headersPlaceholder") })] })), selected?.docsUrl && (_jsxs("a", { href: selected.docsUrl, target: "_blank", rel: "noopener noreferrer", className: "inline-flex items-center gap-1 text-[11px] text-muted-foreground underline hover:text-foreground", children: [t("mcpIntegrations.openSetupDocs"), _jsx(IconExternalLink, { className: "h-3 w-3" })] }))] })), testResult && (_jsxs("div", { className: cn("flex items-start gap-1 rounded-md px-3 py-2 text-[11px] leading-snug", testResult.ok
543
+ ? "bg-green-500/5 text-green-600 dark:text-green-400"
544
+ : "bg-red-500/5 text-red-600 dark:text-red-400"), children: [testResult.ok && (_jsx(IconCheck, { className: "mt-0.5 h-3 w-3 shrink-0" })), _jsx("span", { className: "min-w-0 break-words", children: testResult.message })] })), error && (_jsx("div", { className: "break-words rounded-md bg-red-500/5 px-3 py-2 text-[11px] leading-snug text-red-600 dark:text-red-400", children: error }))] }) }), _jsxs("div", { className: "flex shrink-0 items-center justify-between gap-2 border-t border-border px-7 py-4", children: [!selectedRequiresSetup && (_jsx("button", { type: "button", onClick: runTest, disabled: !url.trim() || busy, className: "rounded-md border border-border bg-background px-3 py-1.5 text-[12px] font-medium text-foreground hover:bg-accent disabled:pointer-events-none disabled:opacity-40", children: t("mcpIntegrations.test") })), !selected && customAuthMode === "oauth" ? (_jsxs("button", { type: "button", onClick: connectCustomWithOAuth, disabled: !name.trim() || !url.trim() || busy, "aria-busy": busy, className: "rounded-md border border-border bg-background px-3 py-1.5 text-[12px] font-medium text-foreground hover:bg-accent disabled:pointer-events-none disabled:opacity-40", children: [busy && (_jsx(IconLoader2, { className: "me-1.5 inline h-3.5 w-3.5 animate-spin" })), t("mcpIntegrations.connectWithOAuth")] })) : null, selectedRequiresSetup ? (_jsxs("div", { className: "ms-auto flex items-center gap-2", children: [selected?.docsUrl ? (_jsxs("a", { href: selected.docsUrl, target: "_blank", rel: "noopener noreferrer", className: "inline-flex min-w-[92px] items-center justify-center gap-1.5 rounded-md border border-border bg-background px-3 py-1.5 text-[12px] font-medium text-foreground hover:bg-accent", children: [t("mcpIntegrations.viewSetup"), _jsx(IconExternalLink, { className: "h-3 w-3" })] })) : null, selected?.authMode === "oauth" && (_jsxs("button", { type: "button", onClick: () => connectWithOAuth(selected), disabled: busy, "aria-busy": busy, className: "inline-flex min-w-[132px] items-center justify-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-[12px] font-medium text-primary-foreground hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-40", children: [busy && (_jsx(IconLoader2, { className: "h-3.5 w-3.5 animate-spin" })), t("mcpIntegrations.continueToConnect")] }))] })) : selected?.authMode === "oauth" ? (_jsxs("button", { type: "button", onClick: () => connectWithOAuth(selected), disabled: !name.trim() || !url.trim() || busy, "aria-busy": busy, className: "inline-flex min-w-[92px] items-center justify-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-[12px] font-medium text-primary-foreground hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-40", children: [busy && _jsx(IconLoader2, { className: "h-3.5 w-3.5 animate-spin" }), t("mcpIntegrations.connectWithOAuth")] })) : !selected && customAuthMode === "oauth" ? null : (_jsxs("button", { type: "button", onClick: submitForm, disabled: !name.trim() || !url.trim() || busy, className: "inline-flex min-w-[92px] items-center justify-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-[12px] font-medium text-primary-foreground hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-40", children: [busy && _jsx(IconLoader2, { className: "h-3.5 w-3.5 animate-spin" }), t("mcpIntegrations.connect")] }))] })] }))] }) }));
476
545
  }