@open-mercato/ai-assistant 0.5.1-develop.2856.35de414092 → 0.5.1-develop.2874.77704bccbd

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 (34) hide show
  1. package/dist/frontend/components/AiDot/AiDot.js +2 -2
  2. package/dist/frontend/components/AiDot/AiDot.js.map +1 -1
  3. package/dist/frontend/components/CommandPalette/CommandFooter.js +2 -2
  4. package/dist/frontend/components/CommandPalette/CommandFooter.js.map +1 -1
  5. package/dist/frontend/components/CommandPalette/CommandPalette.js +4 -4
  6. package/dist/frontend/components/CommandPalette/CommandPalette.js.map +2 -2
  7. package/dist/frontend/components/CommandPalette/DebugPanel.js +1 -1
  8. package/dist/frontend/components/CommandPalette/DebugPanel.js.map +1 -1
  9. package/dist/frontend/components/CommandPalette/MessageBubble.js +2 -2
  10. package/dist/frontend/components/CommandPalette/MessageBubble.js.map +1 -1
  11. package/dist/frontend/components/CommandPalette/ToolCallConfirmation.js +3 -3
  12. package/dist/frontend/components/CommandPalette/ToolCallConfirmation.js.map +2 -2
  13. package/dist/frontend/components/CommandPalette/ToolChatPage.js +1 -1
  14. package/dist/frontend/components/CommandPalette/ToolChatPage.js.map +1 -1
  15. package/dist/frontend/components/DockableChat/DockableChat.js +4 -4
  16. package/dist/frontend/components/DockableChat/DockableChat.js.map +1 -1
  17. package/dist/modules/ai_assistant/components/AiAssistantSettingsPageClient.js +14 -14
  18. package/dist/modules/ai_assistant/components/AiAssistantSettingsPageClient.js.map +2 -2
  19. package/dist/modules/ai_assistant/components/McpConfigDialog.js +3 -3
  20. package/dist/modules/ai_assistant/components/McpConfigDialog.js.map +2 -2
  21. package/dist/modules/ai_assistant/frontend/components/AiAssistantSettingsPageClient.js +14 -14
  22. package/dist/modules/ai_assistant/frontend/components/AiAssistantSettingsPageClient.js.map +2 -2
  23. package/package.json +4 -4
  24. package/src/frontend/components/AiDot/AiDot.tsx +2 -2
  25. package/src/frontend/components/CommandPalette/CommandFooter.tsx +2 -2
  26. package/src/frontend/components/CommandPalette/CommandPalette.tsx +4 -4
  27. package/src/frontend/components/CommandPalette/DebugPanel.tsx +1 -1
  28. package/src/frontend/components/CommandPalette/MessageBubble.tsx +2 -2
  29. package/src/frontend/components/CommandPalette/ToolCallConfirmation.tsx +3 -3
  30. package/src/frontend/components/CommandPalette/ToolChatPage.tsx +1 -1
  31. package/src/frontend/components/DockableChat/DockableChat.tsx +4 -4
  32. package/src/modules/ai_assistant/components/AiAssistantSettingsPageClient.tsx +15 -15
  33. package/src/modules/ai_assistant/components/McpConfigDialog.tsx +3 -3
  34. package/src/modules/ai_assistant/frontend/components/AiAssistantSettingsPageClient.tsx +15 -15
@@ -108,13 +108,13 @@ function AiAssistantSettingsContent() {
108
108
  healthQuery.isFetching && !healthQuery.isLoading && /* @__PURE__ */ jsx(Loader2, { className: "h-3 w-3 animate-spin text-muted-foreground" })
109
109
  ] }),
110
110
  /* @__PURE__ */ jsxs("div", { className: "grid gap-4 sm:grid-cols-3", children: [
111
- /* @__PURE__ */ jsx("div", { className: `p-4 rounded-lg border-2 ${health?.status === "ok" && health.opencode?.healthy ? "border-emerald-500/50 bg-emerald-50/50 dark:bg-emerald-900/10" : "border-destructive/50 bg-destructive/5"}`, children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
111
+ /* @__PURE__ */ jsx("div", { className: `p-4 rounded-lg border-2 ${health?.status === "ok" && health.opencode?.healthy ? "border-status-success-border bg-status-success-bg" : "border-destructive/50 bg-destructive/5"}`, children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
112
112
  /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
113
113
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
114
114
  /* @__PURE__ */ jsx(Server, { className: "h-4 w-4 text-muted-foreground shrink-0" }),
115
115
  /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "OpenCode" })
116
116
  ] }),
117
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1", children: health?.status === "ok" && health.opencode?.healthy ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-emerald-600 dark:text-emerald-400", children: [
117
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1", children: health?.status === "ok" && health.opencode?.healthy ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-status-success-text", children: [
118
118
  /* @__PURE__ */ jsx(CheckCircle2, { className: "h-3 w-3" }),
119
119
  "Connected"
120
120
  ] }) : /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-destructive", children: [
@@ -127,22 +127,22 @@ function AiAssistantSettingsContent() {
127
127
  ] }),
128
128
  /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1 truncate", children: health?.url || "Not configured" })
129
129
  ] }),
130
- health?.status === "ok" && health.opencode?.healthy && /* @__PURE__ */ jsx("div", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-emerald-100 text-emerald-600 dark:bg-emerald-900/40 dark:text-emerald-400 shrink-0", children: /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 3, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) }) })
130
+ health?.status === "ok" && health.opencode?.healthy && /* @__PURE__ */ jsx("div", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-status-success-bg text-status-success-icon shrink-0", children: /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 3, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) }) })
131
131
  ] }) }),
132
132
  (() => {
133
133
  const mcpConnected = health?.mcp && Object.values(health.mcp).some((s) => s.status === "connected");
134
134
  const mcpConnecting = health?.mcp && Object.values(health.mcp).some((s) => s.status === "connecting");
135
135
  const mcpError = health?.mcp && Object.values(health.mcp).find((s) => s.error)?.error;
136
- return /* @__PURE__ */ jsx("div", { className: `p-4 rounded-lg border-2 ${mcpConnected ? "border-emerald-500/50 bg-emerald-50/50 dark:bg-emerald-900/10" : mcpConnecting ? "border-amber-500/50 bg-amber-50/50 dark:bg-amber-900/10" : "border-destructive/50 bg-destructive/5"}`, children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
136
+ return /* @__PURE__ */ jsx("div", { className: `p-4 rounded-lg border-2 ${mcpConnected ? "border-status-success-border bg-status-success-bg" : mcpConnecting ? "border-status-warning-border bg-status-warning-bg" : "border-destructive/50 bg-destructive/5"}`, children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
137
137
  /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
138
138
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
139
139
  /* @__PURE__ */ jsx(Wrench, { className: "h-4 w-4 text-muted-foreground shrink-0" }),
140
140
  /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "MCP Server" })
141
141
  ] }),
142
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1", children: mcpConnected ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-emerald-600 dark:text-emerald-400", children: [
142
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1", children: mcpConnected ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-status-success-text", children: [
143
143
  /* @__PURE__ */ jsx(CheckCircle2, { className: "h-3 w-3" }),
144
144
  "Connected"
145
- ] }) : mcpConnecting ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-amber-600 dark:text-amber-400", children: [
145
+ ] }) : mcpConnecting ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-status-warning-text", children: [
146
146
  /* @__PURE__ */ jsx(Loader2, { className: "h-3 w-3 animate-spin" }),
147
147
  "Connecting..."
148
148
  ] }) : /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-destructive", children: [
@@ -151,16 +151,16 @@ function AiAssistantSettingsContent() {
151
151
  ] }) }),
152
152
  /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1 truncate", children: health?.mcpUrl || "Not configured" })
153
153
  ] }),
154
- mcpConnected && /* @__PURE__ */ jsx("div", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-emerald-100 text-emerald-600 dark:bg-emerald-900/40 dark:text-emerald-400 shrink-0", children: /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 3, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) }) })
154
+ mcpConnected && /* @__PURE__ */ jsx("div", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-status-success-bg text-status-success-icon shrink-0", children: /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 3, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) }) })
155
155
  ] }) });
156
156
  })(),
157
- /* @__PURE__ */ jsx("div", { className: `p-4 rounded-lg border-2 ${health?.search?.available ? "border-emerald-500/50 bg-emerald-50/50 dark:bg-emerald-900/10" : "border-destructive/50 bg-destructive/5"}`, children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
157
+ /* @__PURE__ */ jsx("div", { className: `p-4 rounded-lg border-2 ${health?.search?.available ? "border-status-success-border bg-status-success-bg" : "border-destructive/50 bg-destructive/5"}`, children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
158
158
  /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
159
159
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
160
160
  /* @__PURE__ */ jsx(Database, { className: "h-4 w-4 text-muted-foreground shrink-0" }),
161
161
  /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "Meilisearch" })
162
162
  ] }),
163
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1", children: health?.search?.available ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-emerald-600 dark:text-emerald-400", children: [
163
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1", children: health?.search?.available ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-status-success-text", children: [
164
164
  /* @__PURE__ */ jsx(CheckCircle2, { className: "h-3 w-3" }),
165
165
  "Connected"
166
166
  ] }) : /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-destructive", children: [
@@ -169,17 +169,17 @@ function AiAssistantSettingsContent() {
169
169
  ] }) }),
170
170
  /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1 truncate", children: health?.search?.url || "Not configured" })
171
171
  ] }),
172
- health?.search?.available && /* @__PURE__ */ jsx("div", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-emerald-100 text-emerald-600 dark:bg-emerald-900/40 dark:text-emerald-400 shrink-0", children: /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 3, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) }) })
172
+ health?.search?.available && /* @__PURE__ */ jsx("div", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-status-success-bg text-status-success-icon shrink-0", children: /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 3, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) }) })
173
173
  ] }) })
174
174
  ] }),
175
175
  /* @__PURE__ */ jsxs("div", { className: "mt-4 p-3 rounded-md bg-muted/30 border", children: [
176
176
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm", children: [
177
177
  /* @__PURE__ */ jsx(Key, { className: "h-4 w-4 text-muted-foreground" }),
178
178
  /* @__PURE__ */ jsx("span", { className: "font-medium", children: "MCP Authentication:" }),
179
- settings?.mcpKeyConfigured ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-emerald-600 dark:text-emerald-400 text-xs", children: [
179
+ settings?.mcpKeyConfigured ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-status-success-text text-xs", children: [
180
180
  /* @__PURE__ */ jsx(CheckCircle2, { className: "h-3 w-3" }),
181
181
  "MCP_SERVER_API_KEY configured"
182
- ] }) : /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-amber-600 dark:text-amber-400 text-xs", children: [
182
+ ] }) : /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-status-warning-text text-xs", children: [
183
183
  /* @__PURE__ */ jsx(XCircle, { className: "h-3 w-3" }),
184
184
  "MCP_SERVER_API_KEY not set"
185
185
  ] })
@@ -190,11 +190,11 @@ function AiAssistantSettingsContent() {
190
190
  /* @__PURE__ */ jsx(Server, { className: "h-4 w-4 text-muted-foreground" }),
191
191
  /* @__PURE__ */ jsx("span", { className: "font-medium", children: "LLM Provider:" }),
192
192
  /* @__PURE__ */ jsx("span", { className: "font-medium", children: provider?.name || "Anthropic" }),
193
- provider?.configured ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-emerald-600 dark:text-emerald-400 text-xs", children: [
193
+ provider?.configured ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-status-success-text text-xs", children: [
194
194
  /* @__PURE__ */ jsx(CheckCircle2, { className: "h-3 w-3" }),
195
195
  provider?.envKey,
196
196
  " configured"
197
- ] }) : /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-amber-600 dark:text-amber-400 text-xs", children: [
197
+ ] }) : /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-status-warning-text text-xs", children: [
198
198
  /* @__PURE__ */ jsx(XCircle, { className: "h-3 w-3" }),
199
199
  provider?.envKey || "ANTHROPIC_API_KEY",
200
200
  " not set"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/ai_assistant/components/AiAssistantSettingsPageClient.tsx"],
4
- "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useState } from 'react'\nimport { useQuery } from '@tanstack/react-query'\nimport { Bot, Loader2, CheckCircle2, XCircle, ChevronDown, ChevronRight, Server, Wrench, Eye, EyeOff, Database, Link2, Settings, Key } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Switch } from '@open-mercato/ui/primitives/switch'\nimport { useAiAssistantVisibility } from '../../../frontend/hooks/useAiAssistantVisibility'\nimport McpConfigDialog from './McpConfigDialog'\nimport SessionKeyDialog from './SessionKeyDialog'\n\n// OpenCode health response type\ntype OpenCodeHealthResponse = {\n status: 'ok' | 'error'\n opencode?: {\n healthy: boolean\n version: string\n }\n mcp?: Record<string, { status: string; error?: string }>\n search?: {\n available: boolean\n driver: string | null\n url: string | null\n }\n url: string\n mcpUrl: string\n message?: string\n}\n\n// Provider config type from settings API\ntype ProviderConfig = {\n id: string\n name: string\n model: string\n defaultModel: string\n envKey: string\n configured: boolean\n}\n\ntype SettingsResponse = {\n provider: ProviderConfig\n availableProviders: ProviderConfig[]\n mcpKeyConfigured: boolean\n}\n\n// Tool info type\ntype ToolInfo = {\n name: string\n description: string\n module: string\n inputSchema: Record<string, unknown>\n}\n\n// API fetch functions\nasync function fetchHealth(): Promise<OpenCodeHealthResponse> {\n const res = await fetch('/api/ai_assistant/health')\n if (!res.ok) throw new Error('Failed to fetch health')\n return res.json()\n}\n\nasync function fetchSettings(): Promise<SettingsResponse> {\n const res = await fetch('/api/ai_assistant/settings')\n if (!res.ok) throw new Error('Failed to fetch settings')\n return res.json()\n}\n\nasync function fetchTools(): Promise<{ tools: ToolInfo[] }> {\n const res = await fetch('/api/ai_assistant/tools')\n if (!res.ok) throw new Error('Failed to fetch tools')\n return res.json()\n}\n\nfunction AiAssistantSettingsContent() {\n const [toolsExpanded, setToolsExpanded] = useState(false)\n const [mcpConfigOpen, setMcpConfigOpen] = useState(false)\n const [sessionKeyOpen, setSessionKeyOpen] = useState(false)\n const { isEnabled, toggleEnabled, isLoaded } = useAiAssistantVisibility()\n\n // Open AI Assistant by dispatching global event (triggers main layout's DockableChat)\n const openAiAssistant = () => {\n window.dispatchEvent(new CustomEvent('om:open-ai-chat'))\n }\n\n // Health query - polls every 10 seconds\n const healthQuery = useQuery({\n queryKey: ['ai-assistant', 'health'],\n queryFn: fetchHealth,\n refetchInterval: 10000,\n staleTime: 5000,\n })\n\n // Settings query - no polling needed (static config)\n const settingsQuery = useQuery({\n queryKey: ['ai-assistant', 'settings'],\n queryFn: fetchSettings,\n staleTime: 60000,\n })\n\n // Tools query - no polling needed\n const toolsQuery = useQuery({\n queryKey: ['ai-assistant', 'tools'],\n queryFn: fetchTools,\n staleTime: 60000,\n })\n\n const isLoading = healthQuery.isLoading || settingsQuery.isLoading || toolsQuery.isLoading\n\n if (isLoading) {\n return (\n <div className=\"flex items-center gap-2 text-muted-foreground py-8\">\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n Loading settings...\n </div>\n )\n }\n\n const health = healthQuery.data\n const settings = settingsQuery.data\n const tools = toolsQuery.data?.tools || []\n\n // Group tools by module\n const toolsByModule = tools.reduce<Record<string, ToolInfo[]>>((acc, tool) => {\n const module = tool.module || 'other'\n if (!acc[module]) acc[module] = []\n acc[module].push(tool)\n return acc\n }, {})\n\n const provider = settings?.provider\n\n return (\n <div className=\"flex flex-col gap-6\">\n {/* Header */}\n <div className=\"space-y-1\">\n <h1 className=\"text-2xl font-bold flex items-center gap-2\">\n <Bot className=\"h-6 w-6\" />\n AI Assistant Settings\n </h1>\n <p className=\"text-muted-foreground\">\n Configure and monitor the AI assistant\n </p>\n </div>\n\n {/* AI Assistant Section - Visibility toggle + Test button */}\n <div className=\"rounded-lg border bg-card p-6\">\n <div className=\"flex items-start justify-between\">\n <div className=\"space-y-1\">\n <h2 className=\"text-lg font-semibold flex items-center gap-2\">\n <Bot className=\"h-5 w-5\" />\n AI Assistant\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {isEnabled\n ? 'Visible in header with Cmd+J shortcut enabled.'\n : 'Hidden from header. Enable to show the button and Cmd+J shortcut.'}\n </p>\n </div>\n <div className=\"flex items-center gap-4\">\n <div className=\"flex items-center gap-3 px-4 py-2 rounded-md border bg-muted/30\">\n <span className=\"text-sm font-medium\">Visibility</span>\n {isEnabled ? <Eye className=\"h-4 w-4 text-muted-foreground\" /> : <EyeOff className=\"h-4 w-4 text-muted-foreground\" />}\n <Switch\n checked={isEnabled}\n onCheckedChange={toggleEnabled}\n disabled={!isLoaded}\n />\n </div>\n <Button onClick={openAiAssistant} size=\"default\" className=\"gap-2\">\n <Bot className=\"h-4 w-4\" />\n Open AI Assistant\n </Button>\n </div>\n </div>\n </div>\n\n {/* Connections Section */}\n <div className=\"rounded-lg border bg-card p-6\">\n <div className=\"flex items-center justify-between mb-4\">\n <h2 className=\"text-sm font-semibold flex items-center gap-2\">\n <Link2 className=\"h-4 w-4\" />\n Connections\n </h2>\n {healthQuery.isFetching && !healthQuery.isLoading && (\n <Loader2 className=\"h-3 w-3 animate-spin text-muted-foreground\" />\n )}\n </div>\n <div className=\"grid gap-4 sm:grid-cols-3\">\n {/* OpenCode Server Status */}\n <div className={`p-4 rounded-lg border-2 ${\n health?.status === 'ok' && health.opencode?.healthy\n ? 'border-emerald-500/50 bg-emerald-50/50 dark:bg-emerald-900/10'\n : 'border-destructive/50 bg-destructive/5'\n }`}>\n <div className=\"flex items-start justify-between\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <Server className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <p className=\"text-sm font-medium\">OpenCode</p>\n </div>\n <p className=\"text-xs text-muted-foreground mt-1\">\n {health?.status === 'ok' && health.opencode?.healthy ? (\n <span className=\"flex items-center gap-1 text-emerald-600 dark:text-emerald-400\">\n <CheckCircle2 className=\"h-3 w-3\" />\n Connected\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-destructive\">\n <XCircle className=\"h-3 w-3\" />\n {health?.message || 'Disconnected'}\n </span>\n )}\n </p>\n {health?.opencode?.version && (\n <p className=\"text-xs text-muted-foreground mt-1\">\n v{health.opencode.version}\n </p>\n )}\n <p className=\"text-xs text-muted-foreground mt-1 truncate\">\n {health?.url || 'Not configured'}\n </p>\n </div>\n {health?.status === 'ok' && health.opencode?.healthy && (\n <div className=\"flex h-5 w-5 items-center justify-center rounded-full bg-emerald-100 text-emerald-600 dark:bg-emerald-900/40 dark:text-emerald-400 shrink-0\">\n <svg className=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n )}\n </div>\n </div>\n\n {/* MCP Server Status */}\n {(() => {\n const mcpConnected = health?.mcp && Object.values(health.mcp).some(s => s.status === 'connected')\n const mcpConnecting = health?.mcp && Object.values(health.mcp).some(s => s.status === 'connecting')\n const mcpError = health?.mcp && Object.values(health.mcp).find(s => s.error)?.error\n\n return (\n <div className={`p-4 rounded-lg border-2 ${\n mcpConnected\n ? 'border-emerald-500/50 bg-emerald-50/50 dark:bg-emerald-900/10'\n : mcpConnecting\n ? 'border-amber-500/50 bg-amber-50/50 dark:bg-amber-900/10'\n : 'border-destructive/50 bg-destructive/5'\n }`}>\n <div className=\"flex items-start justify-between\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <Wrench className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <p className=\"text-sm font-medium\">MCP Server</p>\n </div>\n <p className=\"text-xs text-muted-foreground mt-1\">\n {mcpConnected ? (\n <span className=\"flex items-center gap-1 text-emerald-600 dark:text-emerald-400\">\n <CheckCircle2 className=\"h-3 w-3\" />\n Connected\n </span>\n ) : mcpConnecting ? (\n <span className=\"flex items-center gap-1 text-amber-600 dark:text-amber-400\">\n <Loader2 className=\"h-3 w-3 animate-spin\" />\n Connecting...\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-destructive\">\n <XCircle className=\"h-3 w-3\" />\n {mcpError || 'Disconnected'}\n </span>\n )}\n </p>\n <p className=\"text-xs text-muted-foreground mt-1 truncate\">\n {health?.mcpUrl || 'Not configured'}\n </p>\n </div>\n {mcpConnected && (\n <div className=\"flex h-5 w-5 items-center justify-center rounded-full bg-emerald-100 text-emerald-600 dark:bg-emerald-900/40 dark:text-emerald-400 shrink-0\">\n <svg className=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n )}\n </div>\n </div>\n )\n })()}\n\n {/* Meilisearch Status */}\n <div className={`p-4 rounded-lg border-2 ${\n health?.search?.available\n ? 'border-emerald-500/50 bg-emerald-50/50 dark:bg-emerald-900/10'\n : 'border-destructive/50 bg-destructive/5'\n }`}>\n <div className=\"flex items-start justify-between\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <Database className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <p className=\"text-sm font-medium\">Meilisearch</p>\n </div>\n <p className=\"text-xs text-muted-foreground mt-1\">\n {health?.search?.available ? (\n <span className=\"flex items-center gap-1 text-emerald-600 dark:text-emerald-400\">\n <CheckCircle2 className=\"h-3 w-3\" />\n Connected\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-destructive\">\n <XCircle className=\"h-3 w-3\" />\n Not available\n </span>\n )}\n </p>\n <p className=\"text-xs text-muted-foreground mt-1 truncate\">\n {health?.search?.url || 'Not configured'}\n </p>\n </div>\n {health?.search?.available && (\n <div className=\"flex h-5 w-5 items-center justify-center rounded-full bg-emerald-100 text-emerald-600 dark:bg-emerald-900/40 dark:text-emerald-400 shrink-0\">\n <svg className=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n )}\n </div>\n </div>\n </div>\n\n {/* MCP Authentication Status */}\n <div className=\"mt-4 p-3 rounded-md bg-muted/30 border\">\n <div className=\"flex items-center gap-2 text-sm\">\n <Key className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"font-medium\">MCP Authentication:</span>\n {settings?.mcpKeyConfigured ? (\n <span className=\"flex items-center gap-1 text-emerald-600 dark:text-emerald-400 text-xs\">\n <CheckCircle2 className=\"h-3 w-3\" />\n MCP_SERVER_API_KEY configured\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-amber-600 dark:text-amber-400 text-xs\">\n <XCircle className=\"h-3 w-3\" />\n MCP_SERVER_API_KEY not set\n </span>\n )}\n </div>\n <p className=\"text-xs text-muted-foreground mt-1 ml-6\">\n Required for AI to access platform tools via MCP server.\n </p>\n </div>\n\n {/* LLM Provider Status */}\n <div className=\"mt-4 p-3 rounded-md bg-muted/30 border\">\n <div className=\"flex items-center gap-2 text-sm\">\n <Server className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"font-medium\">LLM Provider:</span>\n <span className=\"font-medium\">{provider?.name || 'Anthropic'}</span>\n {provider?.configured ? (\n <span className=\"flex items-center gap-1 text-emerald-600 dark:text-emerald-400 text-xs\">\n <CheckCircle2 className=\"h-3 w-3\" />\n {provider?.envKey} configured\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-amber-600 dark:text-amber-400 text-xs\">\n <XCircle className=\"h-3 w-3\" />\n {provider?.envKey || 'ANTHROPIC_API_KEY'} not set\n </span>\n )}\n </div>\n </div>\n\n <p className=\"text-xs text-muted-foreground mt-4\">\n Meilisearch is required for API endpoint discovery. Endpoints are indexed automatically when the MCP server starts.\n </p>\n </div>\n\n {/* Developer Tools Section */}\n <div className=\"rounded-lg border bg-card p-6\">\n <h2 className=\"text-sm font-semibold mb-4 flex items-center gap-2\">\n <Settings className=\"h-4 w-4\" />\n Developer Tools\n </h2>\n <div className=\"grid gap-4 sm:grid-cols-2\">\n {/* MCP Config Generator */}\n <div className=\"p-4 rounded-lg border bg-muted/30\">\n <div className=\"flex items-start gap-3\">\n <div className=\"p-2 rounded-md bg-primary/10\">\n <Settings className=\"h-5 w-5 text-primary\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <h3 className=\"text-sm font-medium\">MCP Configuration</h3>\n <p className=\"text-xs text-muted-foreground mt-1\">\n Generate config for Claude Code or other MCP clients.\n </p>\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"mt-3\"\n onClick={() => setMcpConfigOpen(true)}\n >\n Generate MCP Config\n </Button>\n </div>\n </div>\n </div>\n\n {/* Session Key Generator */}\n <div className=\"p-4 rounded-lg border bg-muted/30\">\n <div className=\"flex items-start gap-3\">\n <div className=\"p-2 rounded-md bg-primary/10\">\n <Key className=\"h-5 w-5 text-primary\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <h3 className=\"text-sm font-medium\">Session API Key</h3>\n <p className=\"text-xs text-muted-foreground mt-1\">\n Generate a temporary token for programmatic LLM access. Expires after 2 hours.\n </p>\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"mt-3\"\n onClick={() => setSessionKeyOpen(true)}\n >\n Generate Session Key\n </Button>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n {/* Dialogs */}\n <McpConfigDialog\n open={mcpConfigOpen}\n onOpenChange={setMcpConfigOpen}\n mcpUrl={health?.mcpUrl || 'http://localhost:3001'}\n />\n <SessionKeyDialog\n open={sessionKeyOpen}\n onOpenChange={setSessionKeyOpen}\n />\n\n {/* MCP Tools Section */}\n <div className=\"rounded-lg border bg-card p-6\">\n <button\n onClick={() => setToolsExpanded(!toolsExpanded)}\n className=\"w-full flex items-center justify-between text-left\"\n >\n <h2 className=\"text-sm font-semibold flex items-center gap-2\">\n <Wrench className=\"h-4 w-4\" />\n MCP Tools ({tools.length} tools)\n </h2>\n {toolsExpanded ? (\n <ChevronDown className=\"h-4 w-4 text-muted-foreground\" />\n ) : (\n <ChevronRight className=\"h-4 w-4 text-muted-foreground\" />\n )}\n </button>\n\n {toolsExpanded && (\n <div className=\"mt-4 space-y-4\">\n {Object.entries(toolsByModule).map(([module, moduleTools]) => (\n <div key={module} className=\"space-y-2\">\n <h3 className=\"text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n {module}\n </h3>\n <div className=\"space-y-1\">\n {moduleTools.map((tool) => (\n <div key={tool.name} className=\"pl-2 border-l-2 border-muted py-1\">\n <p className=\"text-sm font-medium\">{tool.name}</p>\n <p className=\"text-xs text-muted-foreground\">{tool.description}</p>\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n </div>\n )\n}\n\nexport function AiAssistantSettingsPageClient() {\n return <AiAssistantSettingsContent />\n}\n\nexport default AiAssistantSettingsPageClient\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useState } from 'react'\nimport { useQuery } from '@tanstack/react-query'\nimport { Bot, Loader2, CheckCircle2, XCircle, ChevronDown, ChevronRight, Server, Wrench, Eye, EyeOff, Database, Link2, Settings, Key } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Switch } from '@open-mercato/ui/primitives/switch'\nimport { useAiAssistantVisibility } from '../../../frontend/hooks/useAiAssistantVisibility'\nimport McpConfigDialog from './McpConfigDialog'\nimport SessionKeyDialog from './SessionKeyDialog'\n\n// OpenCode health response type\ntype OpenCodeHealthResponse = {\n status: 'ok' | 'error'\n opencode?: {\n healthy: boolean\n version: string\n }\n mcp?: Record<string, { status: string; error?: string }>\n search?: {\n available: boolean\n driver: string | null\n url: string | null\n }\n url: string\n mcpUrl: string\n message?: string\n}\n\n// Provider config type from settings API\ntype ProviderConfig = {\n id: string\n name: string\n model: string\n defaultModel: string\n envKey: string\n configured: boolean\n}\n\ntype SettingsResponse = {\n provider: ProviderConfig\n availableProviders: ProviderConfig[]\n mcpKeyConfigured: boolean\n}\n\n// Tool info type\ntype ToolInfo = {\n name: string\n description: string\n module: string\n inputSchema: Record<string, unknown>\n}\n\n// API fetch functions\nasync function fetchHealth(): Promise<OpenCodeHealthResponse> {\n const res = await fetch('/api/ai_assistant/health')\n if (!res.ok) throw new Error('Failed to fetch health')\n return res.json()\n}\n\nasync function fetchSettings(): Promise<SettingsResponse> {\n const res = await fetch('/api/ai_assistant/settings')\n if (!res.ok) throw new Error('Failed to fetch settings')\n return res.json()\n}\n\nasync function fetchTools(): Promise<{ tools: ToolInfo[] }> {\n const res = await fetch('/api/ai_assistant/tools')\n if (!res.ok) throw new Error('Failed to fetch tools')\n return res.json()\n}\n\nfunction AiAssistantSettingsContent() {\n const [toolsExpanded, setToolsExpanded] = useState(false)\n const [mcpConfigOpen, setMcpConfigOpen] = useState(false)\n const [sessionKeyOpen, setSessionKeyOpen] = useState(false)\n const { isEnabled, toggleEnabled, isLoaded } = useAiAssistantVisibility()\n\n // Open AI Assistant by dispatching global event (triggers main layout's DockableChat)\n const openAiAssistant = () => {\n window.dispatchEvent(new CustomEvent('om:open-ai-chat'))\n }\n\n // Health query - polls every 10 seconds\n const healthQuery = useQuery({\n queryKey: ['ai-assistant', 'health'],\n queryFn: fetchHealth,\n refetchInterval: 10000,\n staleTime: 5000,\n })\n\n // Settings query - no polling needed (static config)\n const settingsQuery = useQuery({\n queryKey: ['ai-assistant', 'settings'],\n queryFn: fetchSettings,\n staleTime: 60000,\n })\n\n // Tools query - no polling needed\n const toolsQuery = useQuery({\n queryKey: ['ai-assistant', 'tools'],\n queryFn: fetchTools,\n staleTime: 60000,\n })\n\n const isLoading = healthQuery.isLoading || settingsQuery.isLoading || toolsQuery.isLoading\n\n if (isLoading) {\n return (\n <div className=\"flex items-center gap-2 text-muted-foreground py-8\">\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n Loading settings...\n </div>\n )\n }\n\n const health = healthQuery.data\n const settings = settingsQuery.data\n const tools = toolsQuery.data?.tools || []\n\n // Group tools by module\n const toolsByModule = tools.reduce<Record<string, ToolInfo[]>>((acc, tool) => {\n const module = tool.module || 'other'\n if (!acc[module]) acc[module] = []\n acc[module].push(tool)\n return acc\n }, {})\n\n const provider = settings?.provider\n\n return (\n <div className=\"flex flex-col gap-6\">\n {/* Header */}\n <div className=\"space-y-1\">\n <h1 className=\"text-2xl font-bold flex items-center gap-2\">\n <Bot className=\"h-6 w-6\" />\n AI Assistant Settings\n </h1>\n <p className=\"text-muted-foreground\">\n Configure and monitor the AI assistant\n </p>\n </div>\n\n {/* AI Assistant Section - Visibility toggle + Test button */}\n <div className=\"rounded-lg border bg-card p-6\">\n <div className=\"flex items-start justify-between\">\n <div className=\"space-y-1\">\n <h2 className=\"text-lg font-semibold flex items-center gap-2\">\n <Bot className=\"h-5 w-5\" />\n AI Assistant\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {isEnabled\n ? 'Visible in header with Cmd+J shortcut enabled.'\n : 'Hidden from header. Enable to show the button and Cmd+J shortcut.'}\n </p>\n </div>\n <div className=\"flex items-center gap-4\">\n <div className=\"flex items-center gap-3 px-4 py-2 rounded-md border bg-muted/30\">\n <span className=\"text-sm font-medium\">Visibility</span>\n {isEnabled ? <Eye className=\"h-4 w-4 text-muted-foreground\" /> : <EyeOff className=\"h-4 w-4 text-muted-foreground\" />}\n <Switch\n checked={isEnabled}\n onCheckedChange={toggleEnabled}\n disabled={!isLoaded}\n />\n </div>\n <Button onClick={openAiAssistant} size=\"default\" className=\"gap-2\">\n <Bot className=\"h-4 w-4\" />\n Open AI Assistant\n </Button>\n </div>\n </div>\n </div>\n\n {/* Connections Section */}\n <div className=\"rounded-lg border bg-card p-6\">\n <div className=\"flex items-center justify-between mb-4\">\n <h2 className=\"text-sm font-semibold flex items-center gap-2\">\n <Link2 className=\"h-4 w-4\" />\n Connections\n </h2>\n {healthQuery.isFetching && !healthQuery.isLoading && (\n <Loader2 className=\"h-3 w-3 animate-spin text-muted-foreground\" />\n )}\n </div>\n <div className=\"grid gap-4 sm:grid-cols-3\">\n {/* OpenCode Server Status */}\n <div className={`p-4 rounded-lg border-2 ${\n health?.status === 'ok' && health.opencode?.healthy\n ? 'border-status-success-border bg-status-success-bg'\n : 'border-destructive/50 bg-destructive/5'\n }`}>\n <div className=\"flex items-start justify-between\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <Server className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <p className=\"text-sm font-medium\">OpenCode</p>\n </div>\n <p className=\"text-xs text-muted-foreground mt-1\">\n {health?.status === 'ok' && health.opencode?.healthy ? (\n <span className=\"flex items-center gap-1 text-status-success-text\">\n <CheckCircle2 className=\"h-3 w-3\" />\n Connected\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-destructive\">\n <XCircle className=\"h-3 w-3\" />\n {health?.message || 'Disconnected'}\n </span>\n )}\n </p>\n {health?.opencode?.version && (\n <p className=\"text-xs text-muted-foreground mt-1\">\n v{health.opencode.version}\n </p>\n )}\n <p className=\"text-xs text-muted-foreground mt-1 truncate\">\n {health?.url || 'Not configured'}\n </p>\n </div>\n {health?.status === 'ok' && health.opencode?.healthy && (\n <div className=\"flex h-5 w-5 items-center justify-center rounded-full bg-status-success-bg text-status-success-icon shrink-0\">\n <svg className=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n )}\n </div>\n </div>\n\n {/* MCP Server Status */}\n {(() => {\n const mcpConnected = health?.mcp && Object.values(health.mcp).some(s => s.status === 'connected')\n const mcpConnecting = health?.mcp && Object.values(health.mcp).some(s => s.status === 'connecting')\n const mcpError = health?.mcp && Object.values(health.mcp).find(s => s.error)?.error\n\n return (\n <div className={`p-4 rounded-lg border-2 ${\n mcpConnected\n ? 'border-status-success-border bg-status-success-bg'\n : mcpConnecting\n ? 'border-status-warning-border bg-status-warning-bg'\n : 'border-destructive/50 bg-destructive/5'\n }`}>\n <div className=\"flex items-start justify-between\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <Wrench className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <p className=\"text-sm font-medium\">MCP Server</p>\n </div>\n <p className=\"text-xs text-muted-foreground mt-1\">\n {mcpConnected ? (\n <span className=\"flex items-center gap-1 text-status-success-text\">\n <CheckCircle2 className=\"h-3 w-3\" />\n Connected\n </span>\n ) : mcpConnecting ? (\n <span className=\"flex items-center gap-1 text-status-warning-text\">\n <Loader2 className=\"h-3 w-3 animate-spin\" />\n Connecting...\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-destructive\">\n <XCircle className=\"h-3 w-3\" />\n {mcpError || 'Disconnected'}\n </span>\n )}\n </p>\n <p className=\"text-xs text-muted-foreground mt-1 truncate\">\n {health?.mcpUrl || 'Not configured'}\n </p>\n </div>\n {mcpConnected && (\n <div className=\"flex h-5 w-5 items-center justify-center rounded-full bg-status-success-bg text-status-success-icon shrink-0\">\n <svg className=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n )}\n </div>\n </div>\n )\n })()}\n\n {/* Meilisearch Status */}\n <div className={`p-4 rounded-lg border-2 ${\n health?.search?.available\n ? 'border-status-success-border bg-status-success-bg'\n : 'border-destructive/50 bg-destructive/5'\n }`}>\n <div className=\"flex items-start justify-between\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <Database className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n <p className=\"text-sm font-medium\">Meilisearch</p>\n </div>\n <p className=\"text-xs text-muted-foreground mt-1\">\n {health?.search?.available ? (\n <span className=\"flex items-center gap-1 text-status-success-text\">\n <CheckCircle2 className=\"h-3 w-3\" />\n Connected\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-destructive\">\n <XCircle className=\"h-3 w-3\" />\n Not available\n </span>\n )}\n </p>\n <p className=\"text-xs text-muted-foreground mt-1 truncate\">\n {health?.search?.url || 'Not configured'}\n </p>\n </div>\n {health?.search?.available && (\n <div className=\"flex h-5 w-5 items-center justify-center rounded-full bg-status-success-bg text-status-success-icon shrink-0\">\n <svg className=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n )}\n </div>\n </div>\n </div>\n\n {/* MCP Authentication Status */}\n <div className=\"mt-4 p-3 rounded-md bg-muted/30 border\">\n <div className=\"flex items-center gap-2 text-sm\">\n <Key className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"font-medium\">MCP Authentication:</span>\n {settings?.mcpKeyConfigured ? (\n <span className=\"flex items-center gap-1 text-status-success-text text-xs\">\n <CheckCircle2 className=\"h-3 w-3\" />\n MCP_SERVER_API_KEY configured\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-status-warning-text text-xs\">\n <XCircle className=\"h-3 w-3\" />\n MCP_SERVER_API_KEY not set\n </span>\n )}\n </div>\n <p className=\"text-xs text-muted-foreground mt-1 ml-6\">\n Required for AI to access platform tools via MCP server.\n </p>\n </div>\n\n {/* LLM Provider Status */}\n <div className=\"mt-4 p-3 rounded-md bg-muted/30 border\">\n <div className=\"flex items-center gap-2 text-sm\">\n <Server className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"font-medium\">LLM Provider:</span>\n <span className=\"font-medium\">{provider?.name || 'Anthropic'}</span>\n {provider?.configured ? (\n <span className=\"flex items-center gap-1 text-status-success-text text-xs\">\n <CheckCircle2 className=\"h-3 w-3\" />\n {provider?.envKey} configured\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-status-warning-text text-xs\">\n <XCircle className=\"h-3 w-3\" />\n {provider?.envKey || 'ANTHROPIC_API_KEY'} not set\n </span>\n )}\n </div>\n </div>\n\n <p className=\"text-xs text-muted-foreground mt-4\">\n Meilisearch is required for API endpoint discovery. Endpoints are indexed automatically when the MCP server starts.\n </p>\n </div>\n\n {/* Developer Tools Section */}\n <div className=\"rounded-lg border bg-card p-6\">\n <h2 className=\"text-sm font-semibold mb-4 flex items-center gap-2\">\n <Settings className=\"h-4 w-4\" />\n Developer Tools\n </h2>\n <div className=\"grid gap-4 sm:grid-cols-2\">\n {/* MCP Config Generator */}\n <div className=\"p-4 rounded-lg border bg-muted/30\">\n <div className=\"flex items-start gap-3\">\n <div className=\"p-2 rounded-md bg-primary/10\">\n <Settings className=\"h-5 w-5 text-primary\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <h3 className=\"text-sm font-medium\">MCP Configuration</h3>\n <p className=\"text-xs text-muted-foreground mt-1\">\n Generate config for Claude Code or other MCP clients.\n </p>\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"mt-3\"\n onClick={() => setMcpConfigOpen(true)}\n >\n Generate MCP Config\n </Button>\n </div>\n </div>\n </div>\n\n {/* Session Key Generator */}\n <div className=\"p-4 rounded-lg border bg-muted/30\">\n <div className=\"flex items-start gap-3\">\n <div className=\"p-2 rounded-md bg-primary/10\">\n <Key className=\"h-5 w-5 text-primary\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <h3 className=\"text-sm font-medium\">Session API Key</h3>\n <p className=\"text-xs text-muted-foreground mt-1\">\n Generate a temporary token for programmatic LLM access. Expires after 2 hours.\n </p>\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"mt-3\"\n onClick={() => setSessionKeyOpen(true)}\n >\n Generate Session Key\n </Button>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n {/* Dialogs */}\n <McpConfigDialog\n open={mcpConfigOpen}\n onOpenChange={setMcpConfigOpen}\n mcpUrl={health?.mcpUrl || 'http://localhost:3001'}\n />\n <SessionKeyDialog\n open={sessionKeyOpen}\n onOpenChange={setSessionKeyOpen}\n />\n\n {/* MCP Tools Section */}\n <div className=\"rounded-lg border bg-card p-6\">\n <button\n onClick={() => setToolsExpanded(!toolsExpanded)}\n className=\"w-full flex items-center justify-between text-left\"\n >\n <h2 className=\"text-sm font-semibold flex items-center gap-2\">\n <Wrench className=\"h-4 w-4\" />\n MCP Tools ({tools.length} tools)\n </h2>\n {toolsExpanded ? (\n <ChevronDown className=\"h-4 w-4 text-muted-foreground\" />\n ) : (\n <ChevronRight className=\"h-4 w-4 text-muted-foreground\" />\n )}\n </button>\n\n {toolsExpanded && (\n <div className=\"mt-4 space-y-4\">\n {Object.entries(toolsByModule).map(([module, moduleTools]) => (\n <div key={module} className=\"space-y-2\">\n <h3 className=\"text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n {module}\n </h3>\n <div className=\"space-y-1\">\n {moduleTools.map((tool) => (\n <div key={tool.name} className=\"pl-2 border-l-2 border-muted py-1\">\n <p className=\"text-sm font-medium\">{tool.name}</p>\n <p className=\"text-xs text-muted-foreground\">{tool.description}</p>\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n </div>\n )\n}\n\nexport function AiAssistantSettingsPageClient() {\n return <AiAssistantSettingsContent />\n}\n\nexport default AiAssistantSettingsPageClient\n"],
5
+ "mappings": ";AA8GM,SACE,KADF;AA3GN,SAAS,gBAAgB;AACzB,SAAS,gBAAgB;AACzB,SAAS,KAAK,SAAS,cAAc,SAAS,aAAa,cAAc,QAAQ,QAAQ,KAAK,QAAQ,UAAU,OAAO,UAAU,WAAW;AAC5I,SAAS,cAAc;AACvB,SAAS,cAAc;AACvB,SAAS,gCAAgC;AACzC,OAAO,qBAAqB;AAC5B,OAAO,sBAAsB;AA6C7B,eAAe,cAA+C;AAC5D,QAAM,MAAM,MAAM,MAAM,0BAA0B;AAClD,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,wBAAwB;AACrD,SAAO,IAAI,KAAK;AAClB;AAEA,eAAe,gBAA2C;AACxD,QAAM,MAAM,MAAM,MAAM,4BAA4B;AACpD,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACvD,SAAO,IAAI,KAAK;AAClB;AAEA,eAAe,aAA6C;AAC1D,QAAM,MAAM,MAAM,MAAM,yBAAyB;AACjD,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,uBAAuB;AACpD,SAAO,IAAI,KAAK;AAClB;AAEA,SAAS,6BAA6B;AACpC,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAS,KAAK;AACxD,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAS,KAAK;AACxD,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAS,KAAK;AAC1D,QAAM,EAAE,WAAW,eAAe,SAAS,IAAI,yBAAyB;AAGxE,QAAM,kBAAkB,MAAM;AAC5B,WAAO,cAAc,IAAI,YAAY,iBAAiB,CAAC;AAAA,EACzD;AAGA,QAAM,cAAc,SAAS;AAAA,IAC3B,UAAU,CAAC,gBAAgB,QAAQ;AAAA,IACnC,SAAS;AAAA,IACT,iBAAiB;AAAA,IACjB,WAAW;AAAA,EACb,CAAC;AAGD,QAAM,gBAAgB,SAAS;AAAA,IAC7B,UAAU,CAAC,gBAAgB,UAAU;AAAA,IACrC,SAAS;AAAA,IACT,WAAW;AAAA,EACb,CAAC;AAGD,QAAM,aAAa,SAAS;AAAA,IAC1B,UAAU,CAAC,gBAAgB,OAAO;AAAA,IAClC,SAAS;AAAA,IACT,WAAW;AAAA,EACb,CAAC;AAED,QAAM,YAAY,YAAY,aAAa,cAAc,aAAa,WAAW;AAEjF,MAAI,WAAW;AACb,WACE,qBAAC,SAAI,WAAU,sDACb;AAAA,0BAAC,WAAQ,WAAU,wBAAuB;AAAA,MAAE;AAAA,OAE9C;AAAA,EAEJ;AAEA,QAAM,SAAS,YAAY;AAC3B,QAAM,WAAW,cAAc;AAC/B,QAAM,QAAQ,WAAW,MAAM,SAAS,CAAC;AAGzC,QAAM,gBAAgB,MAAM,OAAmC,CAAC,KAAK,SAAS;AAC5E,UAAM,SAAS,KAAK,UAAU;AAC9B,QAAI,CAAC,IAAI,MAAM,EAAG,KAAI,MAAM,IAAI,CAAC;AACjC,QAAI,MAAM,EAAE,KAAK,IAAI;AACrB,WAAO;AAAA,EACT,GAAG,CAAC,CAAC;AAEL,QAAM,WAAW,UAAU;AAE3B,SACE,qBAAC,SAAI,WAAU,uBAEb;AAAA,yBAAC,SAAI,WAAU,aACb;AAAA,2BAAC,QAAG,WAAU,8CACZ;AAAA,4BAAC,OAAI,WAAU,WAAU;AAAA,QAAE;AAAA,SAE7B;AAAA,MACA,oBAAC,OAAE,WAAU,yBAAwB,oDAErC;AAAA,OACF;AAAA,IAGA,oBAAC,SAAI,WAAU,iCACb,+BAAC,SAAI,WAAU,oCACb;AAAA,2BAAC,SAAI,WAAU,aACb;AAAA,6BAAC,QAAG,WAAU,iDACZ;AAAA,8BAAC,OAAI,WAAU,WAAU;AAAA,UAAE;AAAA,WAE7B;AAAA,QACA,oBAAC,OAAE,WAAU,iCACV,sBACG,mDACA,qEACN;AAAA,SACF;AAAA,MACA,qBAAC,SAAI,WAAU,2BACb;AAAA,6BAAC,SAAI,WAAU,mEACb;AAAA,8BAAC,UAAK,WAAU,uBAAsB,wBAAU;AAAA,UAC/C,YAAY,oBAAC,OAAI,WAAU,iCAAgC,IAAK,oBAAC,UAAO,WAAU,iCAAgC;AAAA,UACnH;AAAA,YAAC;AAAA;AAAA,cACC,SAAS;AAAA,cACT,iBAAiB;AAAA,cACjB,UAAU,CAAC;AAAA;AAAA,UACb;AAAA,WACF;AAAA,QACA,qBAAC,UAAO,SAAS,iBAAiB,MAAK,WAAU,WAAU,SACzD;AAAA,8BAAC,OAAI,WAAU,WAAU;AAAA,UAAE;AAAA,WAE7B;AAAA,SACF;AAAA,OACF,GACF;AAAA,IAGA,qBAAC,SAAI,WAAU,iCACb;AAAA,2BAAC,SAAI,WAAU,0CACb;AAAA,6BAAC,QAAG,WAAU,iDACZ;AAAA,8BAAC,SAAM,WAAU,WAAU;AAAA,UAAE;AAAA,WAE/B;AAAA,QACC,YAAY,cAAc,CAAC,YAAY,aACtC,oBAAC,WAAQ,WAAU,8CAA6C;AAAA,SAEpE;AAAA,MACA,qBAAC,SAAI,WAAU,6BAEb;AAAA,4BAAC,SAAI,WAAW,2BACd,QAAQ,WAAW,QAAQ,OAAO,UAAU,UACxC,sDACA,wCACN,IACE,+BAAC,SAAI,WAAU,oCACb;AAAA,+BAAC,SAAI,WAAU,kBACb;AAAA,iCAAC,SAAI,WAAU,2BACb;AAAA,kCAAC,UAAO,WAAU,0CAAyC;AAAA,cAC3D,oBAAC,OAAE,WAAU,uBAAsB,sBAAQ;AAAA,eAC7C;AAAA,YACA,oBAAC,OAAE,WAAU,sCACV,kBAAQ,WAAW,QAAQ,OAAO,UAAU,UAC3C,qBAAC,UAAK,WAAU,oDACd;AAAA,kCAAC,gBAAa,WAAU,WAAU;AAAA,cAAE;AAAA,eAEtC,IAEA,qBAAC,UAAK,WAAU,4CACd;AAAA,kCAAC,WAAQ,WAAU,WAAU;AAAA,cAC5B,QAAQ,WAAW;AAAA,eACtB,GAEJ;AAAA,YACC,QAAQ,UAAU,WACjB,qBAAC,OAAE,WAAU,sCAAqC;AAAA;AAAA,cAC9C,OAAO,SAAS;AAAA,eACpB;AAAA,YAEF,oBAAC,OAAE,WAAU,+CACV,kBAAQ,OAAO,kBAClB;AAAA,aACF;AAAA,UACC,QAAQ,WAAW,QAAQ,OAAO,UAAU,WAC3C,oBAAC,SAAI,WAAU,gHACb,8BAAC,SAAI,WAAU,WAAU,MAAK,QAAO,SAAQ,aAAY,QAAO,gBAAe,aAAa,GAC1F,8BAAC,UAAK,eAAc,SAAQ,gBAAe,SAAQ,GAAE,kBAAiB,GACxE,GACF;AAAA,WAEJ,GACF;AAAA,SAGE,MAAM;AACN,gBAAM,eAAe,QAAQ,OAAO,OAAO,OAAO,OAAO,GAAG,EAAE,KAAK,OAAK,EAAE,WAAW,WAAW;AAChG,gBAAM,gBAAgB,QAAQ,OAAO,OAAO,OAAO,OAAO,GAAG,EAAE,KAAK,OAAK,EAAE,WAAW,YAAY;AAClG,gBAAM,WAAW,QAAQ,OAAO,OAAO,OAAO,OAAO,GAAG,EAAE,KAAK,OAAK,EAAE,KAAK,GAAG;AAE9E,iBACE,oBAAC,SAAI,WAAW,2BACd,eACI,sDACA,gBACE,sDACA,wCACR,IACE,+BAAC,SAAI,WAAU,oCACb;AAAA,iCAAC,SAAI,WAAU,kBACb;AAAA,mCAAC,SAAI,WAAU,2BACb;AAAA,oCAAC,UAAO,WAAU,0CAAyC;AAAA,gBAC3D,oBAAC,OAAE,WAAU,uBAAsB,wBAAU;AAAA,iBAC/C;AAAA,cACA,oBAAC,OAAE,WAAU,sCACV,yBACC,qBAAC,UAAK,WAAU,oDACd;AAAA,oCAAC,gBAAa,WAAU,WAAU;AAAA,gBAAE;AAAA,iBAEtC,IACE,gBACF,qBAAC,UAAK,WAAU,oDACd;AAAA,oCAAC,WAAQ,WAAU,wBAAuB;AAAA,gBAAE;AAAA,iBAE9C,IAEA,qBAAC,UAAK,WAAU,4CACd;AAAA,oCAAC,WAAQ,WAAU,WAAU;AAAA,gBAC5B,YAAY;AAAA,iBACf,GAEJ;AAAA,cACA,oBAAC,OAAE,WAAU,+CACV,kBAAQ,UAAU,kBACrB;AAAA,eACF;AAAA,YACC,gBACC,oBAAC,SAAI,WAAU,gHACb,8BAAC,SAAI,WAAU,WAAU,MAAK,QAAO,SAAQ,aAAY,QAAO,gBAAe,aAAa,GAC1F,8BAAC,UAAK,eAAc,SAAQ,gBAAe,SAAQ,GAAE,kBAAiB,GACxE,GACF;AAAA,aAEJ,GACF;AAAA,QAEJ,GAAG;AAAA,QAGH,oBAAC,SAAI,WAAW,2BACd,QAAQ,QAAQ,YACZ,sDACA,wCACN,IACE,+BAAC,SAAI,WAAU,oCACb;AAAA,+BAAC,SAAI,WAAU,kBACb;AAAA,iCAAC,SAAI,WAAU,2BACb;AAAA,kCAAC,YAAS,WAAU,0CAAyC;AAAA,cAC7D,oBAAC,OAAE,WAAU,uBAAsB,yBAAW;AAAA,eAChD;AAAA,YACA,oBAAC,OAAE,WAAU,sCACV,kBAAQ,QAAQ,YACf,qBAAC,UAAK,WAAU,oDACd;AAAA,kCAAC,gBAAa,WAAU,WAAU;AAAA,cAAE;AAAA,eAEtC,IAEA,qBAAC,UAAK,WAAU,4CACd;AAAA,kCAAC,WAAQ,WAAU,WAAU;AAAA,cAAE;AAAA,eAEjC,GAEJ;AAAA,YACA,oBAAC,OAAE,WAAU,+CACV,kBAAQ,QAAQ,OAAO,kBAC1B;AAAA,aACF;AAAA,UACC,QAAQ,QAAQ,aACf,oBAAC,SAAI,WAAU,gHACb,8BAAC,SAAI,WAAU,WAAU,MAAK,QAAO,SAAQ,aAAY,QAAO,gBAAe,aAAa,GAC1F,8BAAC,UAAK,eAAc,SAAQ,gBAAe,SAAQ,GAAE,kBAAiB,GACxE,GACF;AAAA,WAEJ,GACF;AAAA,SACF;AAAA,MAGA,qBAAC,SAAI,WAAU,0CACb;AAAA,6BAAC,SAAI,WAAU,mCACb;AAAA,8BAAC,OAAI,WAAU,iCAAgC;AAAA,UAC/C,oBAAC,UAAK,WAAU,eAAc,iCAAmB;AAAA,UAChD,UAAU,mBACT,qBAAC,UAAK,WAAU,4DACd;AAAA,gCAAC,gBAAa,WAAU,WAAU;AAAA,YAAE;AAAA,aAEtC,IAEA,qBAAC,UAAK,WAAU,4DACd;AAAA,gCAAC,WAAQ,WAAU,WAAU;AAAA,YAAE;AAAA,aAEjC;AAAA,WAEJ;AAAA,QACA,oBAAC,OAAE,WAAU,2CAA0C,sEAEvD;AAAA,SACF;AAAA,MAGA,oBAAC,SAAI,WAAU,0CACb,+BAAC,SAAI,WAAU,mCACb;AAAA,4BAAC,UAAO,WAAU,iCAAgC;AAAA,QAClD,oBAAC,UAAK,WAAU,eAAc,2BAAa;AAAA,QAC3C,oBAAC,UAAK,WAAU,eAAe,oBAAU,QAAQ,aAAY;AAAA,QAC5D,UAAU,aACT,qBAAC,UAAK,WAAU,4DACd;AAAA,8BAAC,gBAAa,WAAU,WAAU;AAAA,UACjC,UAAU;AAAA,UAAO;AAAA,WACpB,IAEA,qBAAC,UAAK,WAAU,4DACd;AAAA,8BAAC,WAAQ,WAAU,WAAU;AAAA,UAC5B,UAAU,UAAU;AAAA,UAAoB;AAAA,WAC3C;AAAA,SAEJ,GACF;AAAA,MAEA,oBAAC,OAAE,WAAU,sCAAqC,iIAElD;AAAA,OACF;AAAA,IAGA,qBAAC,SAAI,WAAU,iCACb;AAAA,2BAAC,QAAG,WAAU,sDACZ;AAAA,4BAAC,YAAS,WAAU,WAAU;AAAA,QAAE;AAAA,SAElC;AAAA,MACA,qBAAC,SAAI,WAAU,6BAEb;AAAA,4BAAC,SAAI,WAAU,qCACb,+BAAC,SAAI,WAAU,0BACb;AAAA,8BAAC,SAAI,WAAU,gCACb,8BAAC,YAAS,WAAU,wBAAuB,GAC7C;AAAA,UACA,qBAAC,SAAI,WAAU,kBACb;AAAA,gCAAC,QAAG,WAAU,uBAAsB,+BAAiB;AAAA,YACrD,oBAAC,OAAE,WAAU,sCAAqC,mEAElD;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAQ;AAAA,gBACR,WAAU;AAAA,gBACV,SAAS,MAAM,iBAAiB,IAAI;AAAA,gBACrC;AAAA;AAAA,YAED;AAAA,aACF;AAAA,WACF,GACF;AAAA,QAGA,oBAAC,SAAI,WAAU,qCACb,+BAAC,SAAI,WAAU,0BACb;AAAA,8BAAC,SAAI,WAAU,gCACb,8BAAC,OAAI,WAAU,wBAAuB,GACxC;AAAA,UACA,qBAAC,SAAI,WAAU,kBACb;AAAA,gCAAC,QAAG,WAAU,uBAAsB,6BAAe;AAAA,YACnD,oBAAC,OAAE,WAAU,sCAAqC,4FAElD;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAQ;AAAA,gBACR,WAAU;AAAA,gBACV,SAAS,MAAM,kBAAkB,IAAI;AAAA,gBACtC;AAAA;AAAA,YAED;AAAA,aACF;AAAA,WACF,GACF;AAAA,SACF;AAAA,OACF;AAAA,IAGA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,cAAc;AAAA,QACd,QAAQ,QAAQ,UAAU;AAAA;AAAA,IAC5B;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,cAAc;AAAA;AAAA,IAChB;AAAA,IAGA,qBAAC,SAAI,WAAU,iCACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,SAAS,MAAM,iBAAiB,CAAC,aAAa;AAAA,UAC9C,WAAU;AAAA,UAEV;AAAA,iCAAC,QAAG,WAAU,iDACZ;AAAA,kCAAC,UAAO,WAAU,WAAU;AAAA,cAAE;AAAA,cAClB,MAAM;AAAA,cAAO;AAAA,eAC3B;AAAA,YACC,gBACC,oBAAC,eAAY,WAAU,iCAAgC,IAEvD,oBAAC,gBAAa,WAAU,iCAAgC;AAAA;AAAA;AAAA,MAE5D;AAAA,MAEC,iBACC,oBAAC,SAAI,WAAU,kBACZ,iBAAO,QAAQ,aAAa,EAAE,IAAI,CAAC,CAAC,QAAQ,WAAW,MACtD,qBAAC,SAAiB,WAAU,aAC1B;AAAA,4BAAC,QAAG,WAAU,sEACX,kBACH;AAAA,QACA,oBAAC,SAAI,WAAU,aACZ,sBAAY,IAAI,CAAC,SAChB,qBAAC,SAAoB,WAAU,qCAC7B;AAAA,8BAAC,OAAE,WAAU,uBAAuB,eAAK,MAAK;AAAA,UAC9C,oBAAC,OAAE,WAAU,iCAAiC,eAAK,aAAY;AAAA,aAFvD,KAAK,IAGf,CACD,GACH;AAAA,WAXQ,MAYV,CACD,GACH;AAAA,OAEJ;AAAA,KACF;AAEJ;AAEO,SAAS,gCAAgC;AAC9C,SAAO,oBAAC,8BAA2B;AACrC;AAEA,IAAO,wCAAQ;",
6
6
  "names": []
7
7
  }
@@ -124,9 +124,9 @@ function McpConfigDialog({ open, onOpenChange, mcpUrl }) {
124
124
  /* @__PURE__ */ jsx(AlertTriangle, { className: "h-4 w-4" }),
125
125
  error
126
126
  ] }),
127
- apiKey && /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 p-3 bg-amber-50 dark:bg-amber-900/20 rounded-lg border border-amber-200 dark:border-amber-800", children: [
128
- /* @__PURE__ */ jsx(AlertTriangle, { className: "h-4 w-4 text-amber-600 dark:text-amber-400 mt-0.5 shrink-0" }),
129
- /* @__PURE__ */ jsx("p", { className: "text-sm text-amber-700 dark:text-amber-300", children: t("ai_assistant.mcp.saveKeyWarning") })
127
+ apiKey && /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 p-3 bg-status-warning-bg rounded-lg border border-status-warning-border", children: [
128
+ /* @__PURE__ */ jsx(AlertTriangle, { className: "h-4 w-4 text-status-warning-icon mt-0.5 shrink-0" }),
129
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-status-warning-text", children: t("ai_assistant.mcp.saveKeyWarning") })
130
130
  ] })
131
131
  ] }),
132
132
  /* @__PURE__ */ jsxs(DialogFooter, { children: [
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/ai_assistant/components/McpConfigDialog.tsx"],
4
- "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useState } from 'react'\nimport { Copy, RefreshCw, AlertTriangle, Check, Settings } from 'lucide-react'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\ntype Props = {\n open: boolean\n onOpenChange: (next: boolean) => void\n mcpUrl: string\n}\n\ntype ApiKeyResponse = {\n id: string\n name: string\n keyPrefix: string\n secret?: string\n}\n\nexport default function McpConfigDialog({ open, onOpenChange, mcpUrl }: Props) {\n const t = useT()\n const [apiKey, setApiKey] = useState<string | null>(null)\n const [isGenerating, setIsGenerating] = useState(false)\n const [copiedConfig, setCopiedConfig] = useState(false)\n const [copiedKey, setCopiedKey] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const generateApiKey = async () => {\n setIsGenerating(true)\n setError(null)\n try {\n const res = await apiCall<ApiKeyResponse>('/api/api_keys/keys', {\n method: 'POST',\n body: JSON.stringify({\n name: `MCP Config - ${new Date().toLocaleDateString()}`,\n description: 'Generated from AI Assistant settings for MCP client',\n }),\n })\n if (res.ok && res.result?.secret) {\n setApiKey(res.result.secret)\n } else {\n setError(t('ai_assistant.mcp.error.failed'))\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : t('ai_assistant.mcp.error.failed'))\n } finally {\n setIsGenerating(false)\n }\n }\n\n const mcpConfig = {\n mcpServers: {\n 'open-mercato': {\n type: 'http',\n url: `${mcpUrl}/mcp`,\n headers: {\n 'x-api-key': apiKey || 'omk_xxxx.yyyy...',\n },\n },\n },\n }\n\n const configJson = JSON.stringify(mcpConfig, null, 2)\n\n const copyConfig = async () => {\n await navigator.clipboard.writeText(configJson)\n setCopiedConfig(true)\n setTimeout(() => setCopiedConfig(false), 2000)\n }\n\n const copyKey = async () => {\n if (apiKey) {\n await navigator.clipboard.writeText(apiKey)\n setCopiedKey(true)\n setTimeout(() => setCopiedKey(false), 2000)\n }\n }\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n onOpenChange(false)\n }\n },\n [onOpenChange],\n )\n\n const handleClose = () => {\n setApiKey(null)\n setError(null)\n setCopiedConfig(false)\n setCopiedKey(false)\n onOpenChange(false)\n }\n\n return (\n <Dialog open={open} onOpenChange={handleClose}>\n <DialogContent onKeyDown={handleKeyDown} className=\"sm:max-w-2xl\">\n <DialogHeader>\n <DialogTitle className=\"flex items-center gap-2\">\n <Settings className=\"h-5 w-5\" />\n {t('ai_assistant.mcp.title')}\n </DialogTitle>\n <DialogDescription>\n {t('ai_assistant.mcp.description')}\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-4\">\n {/* Config JSON */}\n <div className=\"relative\">\n <pre className=\"bg-muted/50 rounded-lg p-4 text-xs font-mono overflow-x-auto border\">\n {configJson}\n </pre>\n </div>\n\n {/* API Key Section */}\n <div className=\"flex items-center gap-3 flex-wrap\">\n <span className=\"text-sm text-muted-foreground\">{t('ai_assistant.mcp.apiKeyLabel')}</span>\n {apiKey ? (\n <>\n <code className=\"text-xs bg-muted px-2 py-1 rounded font-mono truncate max-w-[200px]\">\n {apiKey.slice(0, 16)}...\n </code>\n <Button variant=\"outline\" size=\"sm\" onClick={copyKey} className=\"gap-1.5\">\n {copiedKey ? <Check className=\"h-3.5 w-3.5\" /> : <Copy className=\"h-3.5 w-3.5\" />}\n {copiedKey ? t('ai_assistant.mcp.copied') : t('ai_assistant.mcp.copyKey')}\n </Button>\n </>\n ) : (\n <span className=\"text-sm text-muted-foreground italic\">{t('ai_assistant.mcp.notGenerated')}</span>\n )}\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={generateApiKey}\n disabled={isGenerating}\n className=\"gap-1.5\"\n >\n <RefreshCw className={`h-3.5 w-3.5 ${isGenerating ? 'animate-spin' : ''}`} />\n {apiKey ? t('ai_assistant.mcp.generateNew') : t('ai_assistant.mcp.generateApiKey')}\n </Button>\n </div>\n\n {error && (\n <div className=\"flex items-center gap-2 text-sm text-destructive\">\n <AlertTriangle className=\"h-4 w-4\" />\n {error}\n </div>\n )}\n\n {apiKey && (\n <div className=\"flex items-start gap-2 p-3 bg-amber-50 dark:bg-amber-900/20 rounded-lg border border-amber-200 dark:border-amber-800\">\n <AlertTriangle className=\"h-4 w-4 text-amber-600 dark:text-amber-400 mt-0.5 shrink-0\" />\n <p className=\"text-sm text-amber-700 dark:text-amber-300\">\n {t('ai_assistant.mcp.saveKeyWarning')}\n </p>\n </div>\n )}\n </div>\n\n <DialogFooter>\n <Button variant=\"outline\" onClick={handleClose}>\n {t('ai_assistant.mcp.close')}\n </Button>\n <Button onClick={copyConfig} className=\"gap-1.5\">\n {copiedConfig ? <Check className=\"h-4 w-4\" /> : <Copy className=\"h-4 w-4\" />}\n {copiedConfig ? t('ai_assistant.mcp.copied') : t('ai_assistant.mcp.copyConfig')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useState } from 'react'\nimport { Copy, RefreshCw, AlertTriangle, Check, Settings } from 'lucide-react'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\ntype Props = {\n open: boolean\n onOpenChange: (next: boolean) => void\n mcpUrl: string\n}\n\ntype ApiKeyResponse = {\n id: string\n name: string\n keyPrefix: string\n secret?: string\n}\n\nexport default function McpConfigDialog({ open, onOpenChange, mcpUrl }: Props) {\n const t = useT()\n const [apiKey, setApiKey] = useState<string | null>(null)\n const [isGenerating, setIsGenerating] = useState(false)\n const [copiedConfig, setCopiedConfig] = useState(false)\n const [copiedKey, setCopiedKey] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const generateApiKey = async () => {\n setIsGenerating(true)\n setError(null)\n try {\n const res = await apiCall<ApiKeyResponse>('/api/api_keys/keys', {\n method: 'POST',\n body: JSON.stringify({\n name: `MCP Config - ${new Date().toLocaleDateString()}`,\n description: 'Generated from AI Assistant settings for MCP client',\n }),\n })\n if (res.ok && res.result?.secret) {\n setApiKey(res.result.secret)\n } else {\n setError(t('ai_assistant.mcp.error.failed'))\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : t('ai_assistant.mcp.error.failed'))\n } finally {\n setIsGenerating(false)\n }\n }\n\n const mcpConfig = {\n mcpServers: {\n 'open-mercato': {\n type: 'http',\n url: `${mcpUrl}/mcp`,\n headers: {\n 'x-api-key': apiKey || 'omk_xxxx.yyyy...',\n },\n },\n },\n }\n\n const configJson = JSON.stringify(mcpConfig, null, 2)\n\n const copyConfig = async () => {\n await navigator.clipboard.writeText(configJson)\n setCopiedConfig(true)\n setTimeout(() => setCopiedConfig(false), 2000)\n }\n\n const copyKey = async () => {\n if (apiKey) {\n await navigator.clipboard.writeText(apiKey)\n setCopiedKey(true)\n setTimeout(() => setCopiedKey(false), 2000)\n }\n }\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n onOpenChange(false)\n }\n },\n [onOpenChange],\n )\n\n const handleClose = () => {\n setApiKey(null)\n setError(null)\n setCopiedConfig(false)\n setCopiedKey(false)\n onOpenChange(false)\n }\n\n return (\n <Dialog open={open} onOpenChange={handleClose}>\n <DialogContent onKeyDown={handleKeyDown} className=\"sm:max-w-2xl\">\n <DialogHeader>\n <DialogTitle className=\"flex items-center gap-2\">\n <Settings className=\"h-5 w-5\" />\n {t('ai_assistant.mcp.title')}\n </DialogTitle>\n <DialogDescription>\n {t('ai_assistant.mcp.description')}\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-4\">\n {/* Config JSON */}\n <div className=\"relative\">\n <pre className=\"bg-muted/50 rounded-lg p-4 text-xs font-mono overflow-x-auto border\">\n {configJson}\n </pre>\n </div>\n\n {/* API Key Section */}\n <div className=\"flex items-center gap-3 flex-wrap\">\n <span className=\"text-sm text-muted-foreground\">{t('ai_assistant.mcp.apiKeyLabel')}</span>\n {apiKey ? (\n <>\n <code className=\"text-xs bg-muted px-2 py-1 rounded font-mono truncate max-w-[200px]\">\n {apiKey.slice(0, 16)}...\n </code>\n <Button variant=\"outline\" size=\"sm\" onClick={copyKey} className=\"gap-1.5\">\n {copiedKey ? <Check className=\"h-3.5 w-3.5\" /> : <Copy className=\"h-3.5 w-3.5\" />}\n {copiedKey ? t('ai_assistant.mcp.copied') : t('ai_assistant.mcp.copyKey')}\n </Button>\n </>\n ) : (\n <span className=\"text-sm text-muted-foreground italic\">{t('ai_assistant.mcp.notGenerated')}</span>\n )}\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={generateApiKey}\n disabled={isGenerating}\n className=\"gap-1.5\"\n >\n <RefreshCw className={`h-3.5 w-3.5 ${isGenerating ? 'animate-spin' : ''}`} />\n {apiKey ? t('ai_assistant.mcp.generateNew') : t('ai_assistant.mcp.generateApiKey')}\n </Button>\n </div>\n\n {error && (\n <div className=\"flex items-center gap-2 text-sm text-destructive\">\n <AlertTriangle className=\"h-4 w-4\" />\n {error}\n </div>\n )}\n\n {apiKey && (\n <div className=\"flex items-start gap-2 p-3 bg-status-warning-bg rounded-lg border border-status-warning-border\">\n <AlertTriangle className=\"h-4 w-4 text-status-warning-icon mt-0.5 shrink-0\" />\n <p className=\"text-sm text-status-warning-text\">\n {t('ai_assistant.mcp.saveKeyWarning')}\n </p>\n </div>\n )}\n </div>\n\n <DialogFooter>\n <Button variant=\"outline\" onClick={handleClose}>\n {t('ai_assistant.mcp.close')}\n </Button>\n <Button onClick={copyConfig} className=\"gap-1.5\">\n {copiedConfig ? <Check className=\"h-4 w-4\" /> : <Copy className=\"h-4 w-4\" />}\n {copiedConfig ? t('ai_assistant.mcp.copied') : t('ai_assistant.mcp.copyConfig')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -93,10 +93,10 @@ function AiAssistantSettingsContent() {
93
93
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm", children: [
94
94
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Provider:" }),
95
95
  /* @__PURE__ */ jsx("span", { className: "font-medium", children: provider?.name || "Anthropic" }),
96
- provider?.configured ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-emerald-600 dark:text-emerald-400 text-xs", children: [
96
+ provider?.configured ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-status-success-text text-xs", children: [
97
97
  /* @__PURE__ */ jsx(CheckCircle2, { className: "h-3 w-3" }),
98
98
  "Configured"
99
- ] }) : /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-amber-600 dark:text-amber-400 text-xs", children: [
99
+ ] }) : /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-status-warning-text text-xs", children: [
100
100
  /* @__PURE__ */ jsx(XCircle, { className: "h-3 w-3" }),
101
101
  "Not configured"
102
102
  ] })
@@ -119,7 +119,7 @@ function AiAssistantSettingsContent() {
119
119
  /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: settings.availableProviders.map((p) => /* @__PURE__ */ jsxs(
120
120
  "div",
121
121
  {
122
- className: `px-2 py-1 rounded text-xs ${p.id === provider?.id ? "bg-primary text-primary-foreground" : p.configured ? "bg-emerald-100 text-emerald-800 dark:bg-emerald-900/30 dark:text-emerald-400" : "bg-muted text-muted-foreground"}`,
122
+ className: `px-2 py-1 rounded text-xs ${p.id === provider?.id ? "bg-primary text-primary-foreground" : p.configured ? "bg-status-success-bg text-status-success-text" : "bg-muted text-muted-foreground"}`,
123
123
  children: [
124
124
  p.name,
125
125
  p.id === provider?.id && " (active)",
@@ -131,7 +131,7 @@ function AiAssistantSettingsContent() {
131
131
  ] }),
132
132
  /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground mt-3", children: [
133
133
  "Set ",
134
- /* @__PURE__ */ jsx("code", { className: "font-mono text-[10px] bg-muted px-1 rounded", children: "OPENCODE_PROVIDER" }),
134
+ /* @__PURE__ */ jsx("code", { className: "font-mono text-overline bg-muted px-1 rounded", children: "OPENCODE_PROVIDER" }),
135
135
  " in .env to change provider (anthropic, openai, google)."
136
136
  ] })
137
137
  ] }),
@@ -143,10 +143,10 @@ function AiAssistantSettingsContent() {
143
143
  /* @__PURE__ */ jsxs("div", { className: "bg-muted/50 rounded-md p-4 space-y-3", children: [
144
144
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm", children: [
145
145
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Full-Text Search:" }),
146
- health?.search?.available ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-emerald-600 dark:text-emerald-400", children: [
146
+ health?.search?.available ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-status-success-text", children: [
147
147
  /* @__PURE__ */ jsx(CheckCircle2, { className: "h-3 w-3" }),
148
148
  "Meilisearch connected"
149
- ] }) : /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-amber-600 dark:text-amber-400", children: [
149
+ ] }) : /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-status-warning-text", children: [
150
150
  /* @__PURE__ */ jsx(XCircle, { className: "h-3 w-3" }),
151
151
  "Not available"
152
152
  ] })
@@ -163,10 +163,10 @@ function AiAssistantSettingsContent() {
163
163
  healthQuery.isFetching && !healthQuery.isLoading && /* @__PURE__ */ jsx(Loader2, { className: "h-3 w-3 animate-spin text-muted-foreground" })
164
164
  ] }),
165
165
  /* @__PURE__ */ jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [
166
- /* @__PURE__ */ jsx("div", { className: `p-4 rounded-lg border-2 ${health?.status === "ok" && health.opencode?.healthy ? "border-emerald-500/50 bg-emerald-50/50 dark:bg-emerald-900/10" : "border-destructive/50 bg-destructive/5"}`, children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
166
+ /* @__PURE__ */ jsx("div", { className: `p-4 rounded-lg border-2 ${health?.status === "ok" && health.opencode?.healthy ? "border-status-success-border bg-status-success-bg" : "border-destructive/50 bg-destructive/5"}`, children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
167
167
  /* @__PURE__ */ jsxs("div", { children: [
168
168
  /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "OpenCode Server" }),
169
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1", children: health?.status === "ok" && health.opencode?.healthy ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-emerald-600 dark:text-emerald-400", children: [
169
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1", children: health?.status === "ok" && health.opencode?.healthy ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-status-success-text", children: [
170
170
  /* @__PURE__ */ jsx(CheckCircle2, { className: "h-3 w-3" }),
171
171
  "Connected"
172
172
  ] }) : /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-destructive", children: [
@@ -179,19 +179,19 @@ function AiAssistantSettingsContent() {
179
179
  ] }),
180
180
  /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1", children: health?.url || "http://localhost:4096" })
181
181
  ] }),
182
- health?.status === "ok" && health.opencode?.healthy && /* @__PURE__ */ jsx("div", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-emerald-100 text-emerald-600 dark:bg-emerald-900/40 dark:text-emerald-400", children: /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 3, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) }) })
182
+ health?.status === "ok" && health.opencode?.healthy && /* @__PURE__ */ jsx("div", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-status-success-bg text-status-success-icon", children: /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 3, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) }) })
183
183
  ] }) }),
184
184
  health?.mcp && Object.entries(health.mcp).map(([name, mcpStatus]) => /* @__PURE__ */ jsx(
185
185
  "div",
186
186
  {
187
- className: `p-4 rounded-lg border-2 ${mcpStatus.status === "connected" ? "border-emerald-500/50 bg-emerald-50/50 dark:bg-emerald-900/10" : mcpStatus.status === "connecting" ? "border-amber-500/50 bg-amber-50/50 dark:bg-amber-900/10" : "border-destructive/50 bg-destructive/5"}`,
187
+ className: `p-4 rounded-lg border-2 ${mcpStatus.status === "connected" ? "border-status-success-border bg-status-success-bg" : mcpStatus.status === "connecting" ? "border-status-warning-border bg-status-warning-bg" : "border-destructive/50 bg-destructive/5"}`,
188
188
  children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
189
189
  /* @__PURE__ */ jsxs("div", { children: [
190
190
  /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "MCP Server" }),
191
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1", children: mcpStatus.status === "connected" ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-emerald-600 dark:text-emerald-400", children: [
191
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1", children: mcpStatus.status === "connected" ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-status-success-text", children: [
192
192
  /* @__PURE__ */ jsx(CheckCircle2, { className: "h-3 w-3" }),
193
193
  "Connected"
194
- ] }) : mcpStatus.status === "connecting" ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-amber-600 dark:text-amber-400", children: [
194
+ ] }) : mcpStatus.status === "connecting" ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-status-warning-text", children: [
195
195
  /* @__PURE__ */ jsx(Loader2, { className: "h-3 w-3 animate-spin" }),
196
196
  "Connecting..."
197
197
  ] }) : /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-destructive", children: [
@@ -201,12 +201,12 @@ function AiAssistantSettingsContent() {
201
201
  /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1", children: name }),
202
202
  /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1", children: "localhost:3001" })
203
203
  ] }),
204
- mcpStatus.status === "connected" && /* @__PURE__ */ jsx("div", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-emerald-100 text-emerald-600 dark:bg-emerald-900/40 dark:text-emerald-400", children: /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 3, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) }) })
204
+ mcpStatus.status === "connected" && /* @__PURE__ */ jsx("div", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-status-success-bg text-status-success-icon", children: /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 3, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) }) })
205
205
  ] })
206
206
  },
207
207
  name
208
208
  )),
209
- (!health?.mcp || Object.keys(health.mcp).length === 0) && /* @__PURE__ */ jsx("div", { className: "p-4 rounded-lg border-2 border-border bg-muted/20", children: /* @__PURE__ */ jsxs("div", { children: [
209
+ (!health?.mcp || Object.keys(health.mcp).length === 0) && /* @__PURE__ */ jsx("div", { className: "p-4 rounded-lg border-2 border-border bg-muted/30", children: /* @__PURE__ */ jsxs("div", { children: [
210
210
  /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "MCP Server" }),
211
211
  /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1", children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
212
212
  /* @__PURE__ */ jsx(XCircle, { className: "h-3 w-3" }),
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/ai_assistant/frontend/components/AiAssistantSettingsPageClient.tsx"],
4
- "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useState } from 'react'\nimport { useQuery } from '@tanstack/react-query'\nimport { Bot, Loader2, CheckCircle2, XCircle, ChevronDown, ChevronRight, Server, Wrench, AlertTriangle } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport {\n CommandPaletteProvider,\n CommandPalette,\n useCommandPaletteContext,\n} from '../../../../frontend'\n\n// OpenCode health response type\ntype OpenCodeHealthResponse = {\n status: 'ok' | 'error'\n opencode?: {\n healthy: boolean\n version: string\n }\n mcp?: Record<string, { status: string; error?: string }>\n search?: {\n available: boolean\n driver: string | null\n }\n url: string\n message?: string\n}\n\n// Provider config type from settings API\ntype ProviderConfig = {\n id: string\n name: string\n model: string\n defaultModel: string\n envKey: string\n configured: boolean\n}\n\ntype SettingsResponse = {\n provider: ProviderConfig\n availableProviders: ProviderConfig[]\n}\n\n// Tool info type\ntype ToolInfo = {\n name: string\n description: string\n module: string\n inputSchema: Record<string, unknown>\n}\n\n// API fetch functions\nasync function fetchHealth(): Promise<OpenCodeHealthResponse> {\n const res = await fetch('/api/ai_assistant/health')\n if (!res.ok) throw new Error('Failed to fetch health')\n return res.json()\n}\n\nasync function fetchSettings(): Promise<SettingsResponse> {\n const res = await fetch('/api/ai_assistant/settings')\n if (!res.ok) throw new Error('Failed to fetch settings')\n return res.json()\n}\n\nasync function fetchTools(): Promise<{ tools: ToolInfo[] }> {\n const res = await fetch('/api/ai_assistant/tools')\n if (!res.ok) throw new Error('Failed to fetch tools')\n return res.json()\n}\n\nfunction AiAssistantSettingsContent() {\n const [toolsExpanded, setToolsExpanded] = useState(false)\n const { setIsOpen } = useCommandPaletteContext()\n\n // Health query - polls every 10 seconds\n const healthQuery = useQuery({\n queryKey: ['ai-assistant', 'health'],\n queryFn: fetchHealth,\n refetchInterval: 10000,\n staleTime: 5000,\n })\n\n // Settings query - no polling needed (static config)\n const settingsQuery = useQuery({\n queryKey: ['ai-assistant', 'settings'],\n queryFn: fetchSettings,\n staleTime: 60000,\n })\n\n // Tools query - no polling needed\n const toolsQuery = useQuery({\n queryKey: ['ai-assistant', 'tools'],\n queryFn: fetchTools,\n staleTime: 60000,\n })\n\n // Open AI Assistant palette\n const openAiAssistant = () => {\n setIsOpen(true)\n }\n\n const isLoading = healthQuery.isLoading || settingsQuery.isLoading || toolsQuery.isLoading\n\n if (isLoading) {\n return (\n <div className=\"flex items-center gap-2 text-muted-foreground py-8\">\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n Loading settings...\n </div>\n )\n }\n\n const health = healthQuery.data\n const settings = settingsQuery.data\n const tools = toolsQuery.data?.tools || []\n\n // Group tools by module\n const toolsByModule = tools.reduce<Record<string, ToolInfo[]>>((acc, tool) => {\n const module = tool.module || 'other'\n if (!acc[module]) acc[module] = []\n acc[module].push(tool)\n return acc\n }, {})\n\n const provider = settings?.provider\n\n return (\n <div className=\"flex flex-col gap-6\">\n {/* Header */}\n <div className=\"space-y-1\">\n <h1 className=\"text-2xl font-bold flex items-center gap-2\">\n <Bot className=\"h-6 w-6\" />\n AI Assistant Settings\n </h1>\n <p className=\"text-muted-foreground\">\n Configure and monitor the AI assistant\n </p>\n </div>\n\n {/* Test AI Assistant Section */}\n <div className=\"rounded-lg border bg-card p-6\">\n <div className=\"flex items-start justify-between\">\n <div className=\"space-y-1\">\n <h2 className=\"text-lg font-semibold flex items-center gap-2\">\n <Bot className=\"h-5 w-5\" />\n Test AI Assistant\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n Click the button to open the AI Assistant command palette.\n </p>\n </div>\n <Button onClick={openAiAssistant} size=\"lg\" className=\"gap-2\">\n <Bot className=\"h-4 w-4\" />\n Open AI Assistant\n </Button>\n </div>\n </div>\n\n {/* Configuration Section */}\n <div className=\"rounded-lg border bg-card p-6\">\n <h2 className=\"text-sm font-semibold mb-4 flex items-center gap-2\">\n <Server className=\"h-4 w-4\" />\n Configuration\n </h2>\n <div className=\"bg-muted/50 rounded-md p-4 space-y-2\">\n <div className=\"flex items-center gap-2 text-sm\">\n <span className=\"text-muted-foreground\">Provider:</span>\n <span className=\"font-medium\">{provider?.name || 'Anthropic'}</span>\n {provider?.configured ? (\n <span className=\"flex items-center gap-1 text-emerald-600 dark:text-emerald-400 text-xs\">\n <CheckCircle2 className=\"h-3 w-3\" />\n Configured\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-amber-600 dark:text-amber-400 text-xs\">\n <XCircle className=\"h-3 w-3\" />\n Not configured\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-2 text-sm\">\n <span className=\"text-muted-foreground\">Model:</span>\n <code className=\"font-mono text-xs bg-background px-1.5 py-0.5 rounded\">{provider?.model || 'claude-haiku-4-5-20251001'}</code>\n </div>\n <div className=\"flex items-center gap-2 text-sm\">\n <span className=\"text-muted-foreground\">Required:</span>\n <span>Set <code className=\"font-mono text-xs bg-background px-1.5 py-0.5 rounded\">{provider?.envKey || 'ANTHROPIC_API_KEY'}</code> in .env</span>\n </div>\n </div>\n\n {/* Available Providers */}\n {settings?.availableProviders && settings.availableProviders.length > 1 && (\n <div className=\"mt-4\">\n <p className=\"text-xs text-muted-foreground mb-2\">Available Providers:</p>\n <div className=\"flex flex-wrap gap-2\">\n {settings.availableProviders.map((p) => (\n <div\n key={p.id}\n className={`px-2 py-1 rounded text-xs ${\n p.id === provider?.id\n ? 'bg-primary text-primary-foreground'\n : p.configured\n ? 'bg-emerald-100 text-emerald-800 dark:bg-emerald-900/30 dark:text-emerald-400'\n : 'bg-muted text-muted-foreground'\n }`}\n >\n {p.name}\n {p.id === provider?.id && ' (active)'}\n {p.id !== provider?.id && p.configured && ' (ready)'}\n </div>\n ))}\n </div>\n </div>\n )}\n\n <p className=\"text-xs text-muted-foreground mt-3\">\n Set <code className=\"font-mono text-[10px] bg-muted px-1 rounded\">OPENCODE_PROVIDER</code> in .env to change provider (anthropic, openai, google).\n </p>\n </div>\n\n {/* Requirements Section */}\n <div className=\"rounded-lg border bg-card p-6\">\n <h2 className=\"text-sm font-semibold mb-4 flex items-center gap-2\">\n <AlertTriangle className=\"h-4 w-4\" />\n Requirements\n </h2>\n <div className=\"bg-muted/50 rounded-md p-4 space-y-3\">\n <div className=\"flex items-center gap-2 text-sm\">\n <span className=\"text-muted-foreground\">Full-Text Search:</span>\n {health?.search?.available ? (\n <span className=\"flex items-center gap-1 text-emerald-600 dark:text-emerald-400\">\n <CheckCircle2 className=\"h-3 w-3\" />\n Meilisearch connected\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-amber-600 dark:text-amber-400\">\n <XCircle className=\"h-3 w-3\" />\n Not available\n </span>\n )}\n </div>\n <p className=\"text-xs text-muted-foreground\">\n A full-text search driver (Meilisearch) is required for API endpoint discovery.\n Endpoints are indexed automatically when the MCP server starts.\n </p>\n </div>\n </div>\n\n {/* OpenCode Connection Section */}\n <div className=\"rounded-lg border bg-card p-6\">\n <div className=\"flex items-center justify-between mb-4\">\n <h2 className=\"text-sm font-semibold flex items-center gap-2\">\n <Server className=\"h-4 w-4\" />\n OpenCode Connection\n </h2>\n {healthQuery.isFetching && !healthQuery.isLoading && (\n <Loader2 className=\"h-3 w-3 animate-spin text-muted-foreground\" />\n )}\n </div>\n <div className=\"grid gap-4 sm:grid-cols-2\">\n {/* OpenCode Server Status */}\n <div className={`p-4 rounded-lg border-2 ${\n health?.status === 'ok' && health.opencode?.healthy\n ? 'border-emerald-500/50 bg-emerald-50/50 dark:bg-emerald-900/10'\n : 'border-destructive/50 bg-destructive/5'\n }`}>\n <div className=\"flex items-start justify-between\">\n <div>\n <p className=\"text-sm font-medium\">OpenCode Server</p>\n <p className=\"text-xs text-muted-foreground mt-1\">\n {health?.status === 'ok' && health.opencode?.healthy ? (\n <span className=\"flex items-center gap-1 text-emerald-600 dark:text-emerald-400\">\n <CheckCircle2 className=\"h-3 w-3\" />\n Connected\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-destructive\">\n <XCircle className=\"h-3 w-3\" />\n {health?.message || 'Disconnected'}\n </span>\n )}\n </p>\n {health?.opencode?.version && (\n <p className=\"text-xs text-muted-foreground mt-1\">\n Version: {health.opencode.version}\n </p>\n )}\n <p className=\"text-xs text-muted-foreground mt-1\">\n {health?.url || 'http://localhost:4096'}\n </p>\n </div>\n {health?.status === 'ok' && health.opencode?.healthy && (\n <div className=\"flex h-5 w-5 items-center justify-center rounded-full bg-emerald-100 text-emerald-600 dark:bg-emerald-900/40 dark:text-emerald-400\">\n <svg className=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n )}\n </div>\n </div>\n\n {/* MCP Server Status */}\n {health?.mcp && Object.entries(health.mcp).map(([name, mcpStatus]) => (\n <div\n key={name}\n className={`p-4 rounded-lg border-2 ${\n mcpStatus.status === 'connected'\n ? 'border-emerald-500/50 bg-emerald-50/50 dark:bg-emerald-900/10'\n : mcpStatus.status === 'connecting'\n ? 'border-amber-500/50 bg-amber-50/50 dark:bg-amber-900/10'\n : 'border-destructive/50 bg-destructive/5'\n }`}\n >\n <div className=\"flex items-start justify-between\">\n <div>\n <p className=\"text-sm font-medium\">MCP Server</p>\n <p className=\"text-xs text-muted-foreground mt-1\">\n {mcpStatus.status === 'connected' ? (\n <span className=\"flex items-center gap-1 text-emerald-600 dark:text-emerald-400\">\n <CheckCircle2 className=\"h-3 w-3\" />\n Connected\n </span>\n ) : mcpStatus.status === 'connecting' ? (\n <span className=\"flex items-center gap-1 text-amber-600 dark:text-amber-400\">\n <Loader2 className=\"h-3 w-3 animate-spin\" />\n Connecting...\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-destructive\">\n <XCircle className=\"h-3 w-3\" />\n {mcpStatus.error || 'Failed'}\n </span>\n )}\n </p>\n <p className=\"text-xs text-muted-foreground mt-1\">{name}</p>\n <p className=\"text-xs text-muted-foreground mt-1\">localhost:3001</p>\n </div>\n {mcpStatus.status === 'connected' && (\n <div className=\"flex h-5 w-5 items-center justify-center rounded-full bg-emerald-100 text-emerald-600 dark:bg-emerald-900/40 dark:text-emerald-400\">\n <svg className=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n )}\n </div>\n </div>\n ))}\n\n {/* Show placeholder if no MCP info */}\n {(!health?.mcp || Object.keys(health.mcp).length === 0) && (\n <div className=\"p-4 rounded-lg border-2 border-border bg-muted/20\">\n <div>\n <p className=\"text-sm font-medium\">MCP Server</p>\n <p className=\"text-xs text-muted-foreground mt-1\">\n <span className=\"flex items-center gap-1\">\n <XCircle className=\"h-3 w-3\" />\n Not connected\n </span>\n </p>\n <p className=\"text-xs text-muted-foreground mt-1\">localhost:3001</p>\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* MCP Tools Section */}\n <div className=\"rounded-lg border bg-card p-6\">\n <button\n onClick={() => setToolsExpanded(!toolsExpanded)}\n className=\"w-full flex items-center justify-between text-left\"\n >\n <h2 className=\"text-sm font-semibold flex items-center gap-2\">\n <Wrench className=\"h-4 w-4\" />\n MCP Tools ({tools.length} tools)\n </h2>\n {toolsExpanded ? (\n <ChevronDown className=\"h-4 w-4 text-muted-foreground\" />\n ) : (\n <ChevronRight className=\"h-4 w-4 text-muted-foreground\" />\n )}\n </button>\n\n {toolsExpanded && (\n <div className=\"mt-4 space-y-4\">\n {Object.entries(toolsByModule).map(([module, moduleTools]) => (\n <div key={module} className=\"space-y-2\">\n <h3 className=\"text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n {module}\n </h3>\n <div className=\"space-y-1\">\n {moduleTools.map((tool) => (\n <div key={tool.name} className=\"pl-2 border-l-2 border-muted py-1\">\n <p className=\"text-sm font-medium\">{tool.name}</p>\n <p className=\"text-xs text-muted-foreground\">{tool.description}</p>\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n </div>\n )\n}\n\nexport function AiAssistantSettingsPageClient() {\n return (\n <CommandPaletteProvider tenantId=\"\" organizationId={null}>\n <AiAssistantSettingsContent />\n <CommandPalette />\n </CommandPaletteProvider>\n )\n}\n\nexport default AiAssistantSettingsPageClient\n"],
5
- "mappings": ";AA0GM,SACE,KADF;AAvGN,SAAS,gBAAgB;AACzB,SAAS,gBAAgB;AACzB,SAAS,KAAK,SAAS,cAAc,SAAS,aAAa,cAAc,QAAQ,QAAQ,qBAAqB;AAC9G,SAAS,cAAc;AACvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AA0CP,eAAe,cAA+C;AAC5D,QAAM,MAAM,MAAM,MAAM,0BAA0B;AAClD,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,wBAAwB;AACrD,SAAO,IAAI,KAAK;AAClB;AAEA,eAAe,gBAA2C;AACxD,QAAM,MAAM,MAAM,MAAM,4BAA4B;AACpD,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,0BAA0B;AACvD,SAAO,IAAI,KAAK;AAClB;AAEA,eAAe,aAA6C;AAC1D,QAAM,MAAM,MAAM,MAAM,yBAAyB;AACjD,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,uBAAuB;AACpD,SAAO,IAAI,KAAK;AAClB;AAEA,SAAS,6BAA6B;AACpC,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAS,KAAK;AACxD,QAAM,EAAE,UAAU,IAAI,yBAAyB;AAG/C,QAAM,cAAc,SAAS;AAAA,IAC3B,UAAU,CAAC,gBAAgB,QAAQ;AAAA,IACnC,SAAS;AAAA,IACT,iBAAiB;AAAA,IACjB,WAAW;AAAA,EACb,CAAC;AAGD,QAAM,gBAAgB,SAAS;AAAA,IAC7B,UAAU,CAAC,gBAAgB,UAAU;AAAA,IACrC,SAAS;AAAA,IACT,WAAW;AAAA,EACb,CAAC;AAGD,QAAM,aAAa,SAAS;AAAA,IAC1B,UAAU,CAAC,gBAAgB,OAAO;AAAA,IAClC,SAAS;AAAA,IACT,WAAW;AAAA,EACb,CAAC;AAGD,QAAM,kBAAkB,MAAM;AAC5B,cAAU,IAAI;AAAA,EAChB;AAEA,QAAM,YAAY,YAAY,aAAa,cAAc,aAAa,WAAW;AAEjF,MAAI,WAAW;AACb,WACE,qBAAC,SAAI,WAAU,sDACb;AAAA,0BAAC,WAAQ,WAAU,wBAAuB;AAAA,MAAE;AAAA,OAE9C;AAAA,EAEJ;AAEA,QAAM,SAAS,YAAY;AAC3B,QAAM,WAAW,cAAc;AAC/B,QAAM,QAAQ,WAAW,MAAM,SAAS,CAAC;AAGzC,QAAM,gBAAgB,MAAM,OAAmC,CAAC,KAAK,SAAS;AAC5E,UAAM,SAAS,KAAK,UAAU;AAC9B,QAAI,CAAC,IAAI,MAAM,EAAG,KAAI,MAAM,IAAI,CAAC;AACjC,QAAI,MAAM,EAAE,KAAK,IAAI;AACrB,WAAO;AAAA,EACT,GAAG,CAAC,CAAC;AAEL,QAAM,WAAW,UAAU;AAE3B,SACE,qBAAC,SAAI,WAAU,uBAEb;AAAA,yBAAC,SAAI,WAAU,aACb;AAAA,2BAAC,QAAG,WAAU,8CACZ;AAAA,4BAAC,OAAI,WAAU,WAAU;AAAA,QAAE;AAAA,SAE7B;AAAA,MACA,oBAAC,OAAE,WAAU,yBAAwB,oDAErC;AAAA,OACF;AAAA,IAGA,oBAAC,SAAI,WAAU,iCACb,+BAAC,SAAI,WAAU,oCACb;AAAA,2BAAC,SAAI,WAAU,aACb;AAAA,6BAAC,QAAG,WAAU,iDACZ;AAAA,8BAAC,OAAI,WAAU,WAAU;AAAA,UAAE;AAAA,WAE7B;AAAA,QACA,oBAAC,OAAE,WAAU,iCAAgC,wEAE7C;AAAA,SACF;AAAA,MACA,qBAAC,UAAO,SAAS,iBAAiB,MAAK,MAAK,WAAU,SACpD;AAAA,4BAAC,OAAI,WAAU,WAAU;AAAA,QAAE;AAAA,SAE7B;AAAA,OACF,GACF;AAAA,IAGA,qBAAC,SAAI,WAAU,iCACb;AAAA,2BAAC,QAAG,WAAU,sDACZ;AAAA,4BAAC,UAAO,WAAU,WAAU;AAAA,QAAE;AAAA,SAEhC;AAAA,MACA,qBAAC,SAAI,WAAU,wCACb;AAAA,6BAAC,SAAI,WAAU,mCACb;AAAA,8BAAC,UAAK,WAAU,yBAAwB,uBAAS;AAAA,UACjD,oBAAC,UAAK,WAAU,eAAe,oBAAU,QAAQ,aAAY;AAAA,UAC5D,UAAU,aACT,qBAAC,UAAK,WAAU,0EACd;AAAA,gCAAC,gBAAa,WAAU,WAAU;AAAA,YAAE;AAAA,aAEtC,IAEA,qBAAC,UAAK,WAAU,sEACd;AAAA,gCAAC,WAAQ,WAAU,WAAU;AAAA,YAAE;AAAA,aAEjC;AAAA,WAEJ;AAAA,QACA,qBAAC,SAAI,WAAU,mCACb;AAAA,8BAAC,UAAK,WAAU,yBAAwB,oBAAM;AAAA,UAC9C,oBAAC,UAAK,WAAU,yDAAyD,oBAAU,SAAS,6BAA4B;AAAA,WAC1H;AAAA,QACA,qBAAC,SAAI,WAAU,mCACb;AAAA,8BAAC,UAAK,WAAU,yBAAwB,uBAAS;AAAA,UACjD,qBAAC,UAAK;AAAA;AAAA,YAAI,oBAAC,UAAK,WAAU,yDAAyD,oBAAU,UAAU,qBAAoB;AAAA,YAAO;AAAA,aAAQ;AAAA,WAC5I;AAAA,SACF;AAAA,MAGC,UAAU,sBAAsB,SAAS,mBAAmB,SAAS,KACpE,qBAAC,SAAI,WAAU,QACb;AAAA,4BAAC,OAAE,WAAU,sCAAqC,kCAAoB;AAAA,QACtE,oBAAC,SAAI,WAAU,wBACZ,mBAAS,mBAAmB,IAAI,CAAC,MAChC;AAAA,UAAC;AAAA;AAAA,YAEC,WAAW,6BACT,EAAE,OAAO,UAAU,KACf,uCACA,EAAE,aACA,iFACA,gCACR;AAAA,YAEC;AAAA,gBAAE;AAAA,cACF,EAAE,OAAO,UAAU,MAAM;AAAA,cACzB,EAAE,OAAO,UAAU,MAAM,EAAE,cAAc;AAAA;AAAA;AAAA,UAXrC,EAAE;AAAA,QAYT,CACD,GACH;AAAA,SACF;AAAA,MAGF,qBAAC,OAAE,WAAU,sCAAqC;AAAA;AAAA,QAC5C,oBAAC,UAAK,WAAU,+CAA8C,+BAAiB;AAAA,QAAO;AAAA,SAC5F;AAAA,OACF;AAAA,IAGA,qBAAC,SAAI,WAAU,iCACb;AAAA,2BAAC,QAAG,WAAU,sDACZ;AAAA,4BAAC,iBAAc,WAAU,WAAU;AAAA,QAAE;AAAA,SAEvC;AAAA,MACA,qBAAC,SAAI,WAAU,wCACb;AAAA,6BAAC,SAAI,WAAU,mCACb;AAAA,8BAAC,UAAK,WAAU,yBAAwB,+BAAiB;AAAA,UACxD,QAAQ,QAAQ,YACf,qBAAC,UAAK,WAAU,kEACd;AAAA,gCAAC,gBAAa,WAAU,WAAU;AAAA,YAAE;AAAA,aAEtC,IAEA,qBAAC,UAAK,WAAU,8DACd;AAAA,gCAAC,WAAQ,WAAU,WAAU;AAAA,YAAE;AAAA,aAEjC;AAAA,WAEJ;AAAA,QACA,oBAAC,OAAE,WAAU,iCAAgC,6JAG7C;AAAA,SACF;AAAA,OACF;AAAA,IAGA,qBAAC,SAAI,WAAU,iCACb;AAAA,2BAAC,SAAI,WAAU,0CACb;AAAA,6BAAC,QAAG,WAAU,iDACZ;AAAA,8BAAC,UAAO,WAAU,WAAU;AAAA,UAAE;AAAA,WAEhC;AAAA,QACC,YAAY,cAAc,CAAC,YAAY,aACtC,oBAAC,WAAQ,WAAU,8CAA6C;AAAA,SAEpE;AAAA,MACA,qBAAC,SAAI,WAAU,6BAEb;AAAA,4BAAC,SAAI,WAAW,2BACd,QAAQ,WAAW,QAAQ,OAAO,UAAU,UACxC,kEACA,wCACN,IACE,+BAAC,SAAI,WAAU,oCACb;AAAA,+BAAC,SACC;AAAA,gCAAC,OAAE,WAAU,uBAAsB,6BAAe;AAAA,YAClD,oBAAC,OAAE,WAAU,sCACV,kBAAQ,WAAW,QAAQ,OAAO,UAAU,UAC3C,qBAAC,UAAK,WAAU,kEACd;AAAA,kCAAC,gBAAa,WAAU,WAAU;AAAA,cAAE;AAAA,eAEtC,IAEA,qBAAC,UAAK,WAAU,4CACd;AAAA,kCAAC,WAAQ,WAAU,WAAU;AAAA,cAC5B,QAAQ,WAAW;AAAA,eACtB,GAEJ;AAAA,YACC,QAAQ,UAAU,WACjB,qBAAC,OAAE,WAAU,sCAAqC;AAAA;AAAA,cACtC,OAAO,SAAS;AAAA,eAC5B;AAAA,YAEF,oBAAC,OAAE,WAAU,sCACV,kBAAQ,OAAO,yBAClB;AAAA,aACF;AAAA,UACC,QAAQ,WAAW,QAAQ,OAAO,UAAU,WAC3C,oBAAC,SAAI,WAAU,sIACb,8BAAC,SAAI,WAAU,WAAU,MAAK,QAAO,SAAQ,aAAY,QAAO,gBAAe,aAAa,GAC1F,8BAAC,UAAK,eAAc,SAAQ,gBAAe,SAAQ,GAAE,kBAAiB,GACxE,GACF;AAAA,WAEJ,GACF;AAAA,QAGC,QAAQ,OAAO,OAAO,QAAQ,OAAO,GAAG,EAAE,IAAI,CAAC,CAAC,MAAM,SAAS,MAC9D;AAAA,UAAC;AAAA;AAAA,YAEC,WAAW,2BACT,UAAU,WAAW,cACjB,kEACA,UAAU,WAAW,eACnB,4DACA,wCACR;AAAA,YAEA,+BAAC,SAAI,WAAU,oCACb;AAAA,mCAAC,SACC;AAAA,oCAAC,OAAE,WAAU,uBAAsB,wBAAU;AAAA,gBAC7C,oBAAC,OAAE,WAAU,sCACV,oBAAU,WAAW,cACpB,qBAAC,UAAK,WAAU,kEACd;AAAA,sCAAC,gBAAa,WAAU,WAAU;AAAA,kBAAE;AAAA,mBAEtC,IACE,UAAU,WAAW,eACvB,qBAAC,UAAK,WAAU,8DACd;AAAA,sCAAC,WAAQ,WAAU,wBAAuB;AAAA,kBAAE;AAAA,mBAE9C,IAEA,qBAAC,UAAK,WAAU,4CACd;AAAA,sCAAC,WAAQ,WAAU,WAAU;AAAA,kBAC5B,UAAU,SAAS;AAAA,mBACtB,GAEJ;AAAA,gBACA,oBAAC,OAAE,WAAU,sCAAsC,gBAAK;AAAA,gBACxD,oBAAC,OAAE,WAAU,sCAAqC,4BAAc;AAAA,iBAClE;AAAA,cACC,UAAU,WAAW,eACpB,oBAAC,SAAI,WAAU,sIACb,8BAAC,SAAI,WAAU,WAAU,MAAK,QAAO,SAAQ,aAAY,QAAO,gBAAe,aAAa,GAC1F,8BAAC,UAAK,eAAc,SAAQ,gBAAe,SAAQ,GAAE,kBAAiB,GACxE,GACF;AAAA,eAEJ;AAAA;AAAA,UAxCK;AAAA,QAyCP,CACD;AAAA,SAGC,CAAC,QAAQ,OAAO,OAAO,KAAK,OAAO,GAAG,EAAE,WAAW,MACnD,oBAAC,SAAI,WAAU,qDACb,+BAAC,SACC;AAAA,8BAAC,OAAE,WAAU,uBAAsB,wBAAU;AAAA,UAC7C,oBAAC,OAAE,WAAU,sCACX,+BAAC,UAAK,WAAU,2BACd;AAAA,gCAAC,WAAQ,WAAU,WAAU;AAAA,YAAE;AAAA,aAEjC,GACF;AAAA,UACA,oBAAC,OAAE,WAAU,sCAAqC,4BAAc;AAAA,WAClE,GACF;AAAA,SAEJ;AAAA,OACF;AAAA,IAGA,qBAAC,SAAI,WAAU,iCACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,SAAS,MAAM,iBAAiB,CAAC,aAAa;AAAA,UAC9C,WAAU;AAAA,UAEV;AAAA,iCAAC,QAAG,WAAU,iDACZ;AAAA,kCAAC,UAAO,WAAU,WAAU;AAAA,cAAE;AAAA,cAClB,MAAM;AAAA,cAAO;AAAA,eAC3B;AAAA,YACC,gBACC,oBAAC,eAAY,WAAU,iCAAgC,IAEvD,oBAAC,gBAAa,WAAU,iCAAgC;AAAA;AAAA;AAAA,MAE5D;AAAA,MAEC,iBACC,oBAAC,SAAI,WAAU,kBACZ,iBAAO,QAAQ,aAAa,EAAE,IAAI,CAAC,CAAC,QAAQ,WAAW,MACtD,qBAAC,SAAiB,WAAU,aAC1B;AAAA,4BAAC,QAAG,WAAU,sEACX,kBACH;AAAA,QACA,oBAAC,SAAI,WAAU,aACZ,sBAAY,IAAI,CAAC,SAChB,qBAAC,SAAoB,WAAU,qCAC7B;AAAA,8BAAC,OAAE,WAAU,uBAAuB,eAAK,MAAK;AAAA,UAC9C,oBAAC,OAAE,WAAU,iCAAiC,eAAK,aAAY;AAAA,aAFvD,KAAK,IAGf,CACD,GACH;AAAA,WAXQ,MAYV,CACD,GACH;AAAA,OAEJ;AAAA,KACF;AAEJ;AAEO,SAAS,gCAAgC;AAC9C,SACE,qBAAC,0BAAuB,UAAS,IAAG,gBAAgB,MAClD;AAAA,wBAAC,8BAA2B;AAAA,IAC5B,oBAAC,kBAAe;AAAA,KAClB;AAEJ;AAEA,IAAO,wCAAQ;",
4
+ "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useState } from 'react'\nimport { useQuery } from '@tanstack/react-query'\nimport { Bot, Loader2, CheckCircle2, XCircle, ChevronDown, ChevronRight, Server, Wrench, AlertTriangle } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport {\n CommandPaletteProvider,\n CommandPalette,\n useCommandPaletteContext,\n} from '../../../../frontend'\n\n// OpenCode health response type\ntype OpenCodeHealthResponse = {\n status: 'ok' | 'error'\n opencode?: {\n healthy: boolean\n version: string\n }\n mcp?: Record<string, { status: string; error?: string }>\n search?: {\n available: boolean\n driver: string | null\n }\n url: string\n message?: string\n}\n\n// Provider config type from settings API\ntype ProviderConfig = {\n id: string\n name: string\n model: string\n defaultModel: string\n envKey: string\n configured: boolean\n}\n\ntype SettingsResponse = {\n provider: ProviderConfig\n availableProviders: ProviderConfig[]\n}\n\n// Tool info type\ntype ToolInfo = {\n name: string\n description: string\n module: string\n inputSchema: Record<string, unknown>\n}\n\n// API fetch functions\nasync function fetchHealth(): Promise<OpenCodeHealthResponse> {\n const res = await fetch('/api/ai_assistant/health')\n if (!res.ok) throw new Error('Failed to fetch health')\n return res.json()\n}\n\nasync function fetchSettings(): Promise<SettingsResponse> {\n const res = await fetch('/api/ai_assistant/settings')\n if (!res.ok) throw new Error('Failed to fetch settings')\n return res.json()\n}\n\nasync function fetchTools(): Promise<{ tools: ToolInfo[] }> {\n const res = await fetch('/api/ai_assistant/tools')\n if (!res.ok) throw new Error('Failed to fetch tools')\n return res.json()\n}\n\nfunction AiAssistantSettingsContent() {\n const [toolsExpanded, setToolsExpanded] = useState(false)\n const { setIsOpen } = useCommandPaletteContext()\n\n // Health query - polls every 10 seconds\n const healthQuery = useQuery({\n queryKey: ['ai-assistant', 'health'],\n queryFn: fetchHealth,\n refetchInterval: 10000,\n staleTime: 5000,\n })\n\n // Settings query - no polling needed (static config)\n const settingsQuery = useQuery({\n queryKey: ['ai-assistant', 'settings'],\n queryFn: fetchSettings,\n staleTime: 60000,\n })\n\n // Tools query - no polling needed\n const toolsQuery = useQuery({\n queryKey: ['ai-assistant', 'tools'],\n queryFn: fetchTools,\n staleTime: 60000,\n })\n\n // Open AI Assistant palette\n const openAiAssistant = () => {\n setIsOpen(true)\n }\n\n const isLoading = healthQuery.isLoading || settingsQuery.isLoading || toolsQuery.isLoading\n\n if (isLoading) {\n return (\n <div className=\"flex items-center gap-2 text-muted-foreground py-8\">\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n Loading settings...\n </div>\n )\n }\n\n const health = healthQuery.data\n const settings = settingsQuery.data\n const tools = toolsQuery.data?.tools || []\n\n // Group tools by module\n const toolsByModule = tools.reduce<Record<string, ToolInfo[]>>((acc, tool) => {\n const module = tool.module || 'other'\n if (!acc[module]) acc[module] = []\n acc[module].push(tool)\n return acc\n }, {})\n\n const provider = settings?.provider\n\n return (\n <div className=\"flex flex-col gap-6\">\n {/* Header */}\n <div className=\"space-y-1\">\n <h1 className=\"text-2xl font-bold flex items-center gap-2\">\n <Bot className=\"h-6 w-6\" />\n AI Assistant Settings\n </h1>\n <p className=\"text-muted-foreground\">\n Configure and monitor the AI assistant\n </p>\n </div>\n\n {/* Test AI Assistant Section */}\n <div className=\"rounded-lg border bg-card p-6\">\n <div className=\"flex items-start justify-between\">\n <div className=\"space-y-1\">\n <h2 className=\"text-lg font-semibold flex items-center gap-2\">\n <Bot className=\"h-5 w-5\" />\n Test AI Assistant\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n Click the button to open the AI Assistant command palette.\n </p>\n </div>\n <Button onClick={openAiAssistant} size=\"lg\" className=\"gap-2\">\n <Bot className=\"h-4 w-4\" />\n Open AI Assistant\n </Button>\n </div>\n </div>\n\n {/* Configuration Section */}\n <div className=\"rounded-lg border bg-card p-6\">\n <h2 className=\"text-sm font-semibold mb-4 flex items-center gap-2\">\n <Server className=\"h-4 w-4\" />\n Configuration\n </h2>\n <div className=\"bg-muted/50 rounded-md p-4 space-y-2\">\n <div className=\"flex items-center gap-2 text-sm\">\n <span className=\"text-muted-foreground\">Provider:</span>\n <span className=\"font-medium\">{provider?.name || 'Anthropic'}</span>\n {provider?.configured ? (\n <span className=\"flex items-center gap-1 text-status-success-text text-xs\">\n <CheckCircle2 className=\"h-3 w-3\" />\n Configured\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-status-warning-text text-xs\">\n <XCircle className=\"h-3 w-3\" />\n Not configured\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-2 text-sm\">\n <span className=\"text-muted-foreground\">Model:</span>\n <code className=\"font-mono text-xs bg-background px-1.5 py-0.5 rounded\">{provider?.model || 'claude-haiku-4-5-20251001'}</code>\n </div>\n <div className=\"flex items-center gap-2 text-sm\">\n <span className=\"text-muted-foreground\">Required:</span>\n <span>Set <code className=\"font-mono text-xs bg-background px-1.5 py-0.5 rounded\">{provider?.envKey || 'ANTHROPIC_API_KEY'}</code> in .env</span>\n </div>\n </div>\n\n {/* Available Providers */}\n {settings?.availableProviders && settings.availableProviders.length > 1 && (\n <div className=\"mt-4\">\n <p className=\"text-xs text-muted-foreground mb-2\">Available Providers:</p>\n <div className=\"flex flex-wrap gap-2\">\n {settings.availableProviders.map((p) => (\n <div\n key={p.id}\n className={`px-2 py-1 rounded text-xs ${\n p.id === provider?.id\n ? 'bg-primary text-primary-foreground'\n : p.configured\n ? 'bg-status-success-bg text-status-success-text'\n : 'bg-muted text-muted-foreground'\n }`}\n >\n {p.name}\n {p.id === provider?.id && ' (active)'}\n {p.id !== provider?.id && p.configured && ' (ready)'}\n </div>\n ))}\n </div>\n </div>\n )}\n\n <p className=\"text-xs text-muted-foreground mt-3\">\n Set <code className=\"font-mono text-overline bg-muted px-1 rounded\">OPENCODE_PROVIDER</code> in .env to change provider (anthropic, openai, google).\n </p>\n </div>\n\n {/* Requirements Section */}\n <div className=\"rounded-lg border bg-card p-6\">\n <h2 className=\"text-sm font-semibold mb-4 flex items-center gap-2\">\n <AlertTriangle className=\"h-4 w-4\" />\n Requirements\n </h2>\n <div className=\"bg-muted/50 rounded-md p-4 space-y-3\">\n <div className=\"flex items-center gap-2 text-sm\">\n <span className=\"text-muted-foreground\">Full-Text Search:</span>\n {health?.search?.available ? (\n <span className=\"flex items-center gap-1 text-status-success-text\">\n <CheckCircle2 className=\"h-3 w-3\" />\n Meilisearch connected\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-status-warning-text\">\n <XCircle className=\"h-3 w-3\" />\n Not available\n </span>\n )}\n </div>\n <p className=\"text-xs text-muted-foreground\">\n A full-text search driver (Meilisearch) is required for API endpoint discovery.\n Endpoints are indexed automatically when the MCP server starts.\n </p>\n </div>\n </div>\n\n {/* OpenCode Connection Section */}\n <div className=\"rounded-lg border bg-card p-6\">\n <div className=\"flex items-center justify-between mb-4\">\n <h2 className=\"text-sm font-semibold flex items-center gap-2\">\n <Server className=\"h-4 w-4\" />\n OpenCode Connection\n </h2>\n {healthQuery.isFetching && !healthQuery.isLoading && (\n <Loader2 className=\"h-3 w-3 animate-spin text-muted-foreground\" />\n )}\n </div>\n <div className=\"grid gap-4 sm:grid-cols-2\">\n {/* OpenCode Server Status */}\n <div className={`p-4 rounded-lg border-2 ${\n health?.status === 'ok' && health.opencode?.healthy\n ? 'border-status-success-border bg-status-success-bg'\n : 'border-destructive/50 bg-destructive/5'\n }`}>\n <div className=\"flex items-start justify-between\">\n <div>\n <p className=\"text-sm font-medium\">OpenCode Server</p>\n <p className=\"text-xs text-muted-foreground mt-1\">\n {health?.status === 'ok' && health.opencode?.healthy ? (\n <span className=\"flex items-center gap-1 text-status-success-text\">\n <CheckCircle2 className=\"h-3 w-3\" />\n Connected\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-destructive\">\n <XCircle className=\"h-3 w-3\" />\n {health?.message || 'Disconnected'}\n </span>\n )}\n </p>\n {health?.opencode?.version && (\n <p className=\"text-xs text-muted-foreground mt-1\">\n Version: {health.opencode.version}\n </p>\n )}\n <p className=\"text-xs text-muted-foreground mt-1\">\n {health?.url || 'http://localhost:4096'}\n </p>\n </div>\n {health?.status === 'ok' && health.opencode?.healthy && (\n <div className=\"flex h-5 w-5 items-center justify-center rounded-full bg-status-success-bg text-status-success-icon\">\n <svg className=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n )}\n </div>\n </div>\n\n {/* MCP Server Status */}\n {health?.mcp && Object.entries(health.mcp).map(([name, mcpStatus]) => (\n <div\n key={name}\n className={`p-4 rounded-lg border-2 ${\n mcpStatus.status === 'connected'\n ? 'border-status-success-border bg-status-success-bg'\n : mcpStatus.status === 'connecting'\n ? 'border-status-warning-border bg-status-warning-bg'\n : 'border-destructive/50 bg-destructive/5'\n }`}\n >\n <div className=\"flex items-start justify-between\">\n <div>\n <p className=\"text-sm font-medium\">MCP Server</p>\n <p className=\"text-xs text-muted-foreground mt-1\">\n {mcpStatus.status === 'connected' ? (\n <span className=\"flex items-center gap-1 text-status-success-text\">\n <CheckCircle2 className=\"h-3 w-3\" />\n Connected\n </span>\n ) : mcpStatus.status === 'connecting' ? (\n <span className=\"flex items-center gap-1 text-status-warning-text\">\n <Loader2 className=\"h-3 w-3 animate-spin\" />\n Connecting...\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-destructive\">\n <XCircle className=\"h-3 w-3\" />\n {mcpStatus.error || 'Failed'}\n </span>\n )}\n </p>\n <p className=\"text-xs text-muted-foreground mt-1\">{name}</p>\n <p className=\"text-xs text-muted-foreground mt-1\">localhost:3001</p>\n </div>\n {mcpStatus.status === 'connected' && (\n <div className=\"flex h-5 w-5 items-center justify-center rounded-full bg-status-success-bg text-status-success-icon\">\n <svg className=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n )}\n </div>\n </div>\n ))}\n\n {/* Show placeholder if no MCP info */}\n {(!health?.mcp || Object.keys(health.mcp).length === 0) && (\n <div className=\"p-4 rounded-lg border-2 border-border bg-muted/30\">\n <div>\n <p className=\"text-sm font-medium\">MCP Server</p>\n <p className=\"text-xs text-muted-foreground mt-1\">\n <span className=\"flex items-center gap-1\">\n <XCircle className=\"h-3 w-3\" />\n Not connected\n </span>\n </p>\n <p className=\"text-xs text-muted-foreground mt-1\">localhost:3001</p>\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* MCP Tools Section */}\n <div className=\"rounded-lg border bg-card p-6\">\n <button\n onClick={() => setToolsExpanded(!toolsExpanded)}\n className=\"w-full flex items-center justify-between text-left\"\n >\n <h2 className=\"text-sm font-semibold flex items-center gap-2\">\n <Wrench className=\"h-4 w-4\" />\n MCP Tools ({tools.length} tools)\n </h2>\n {toolsExpanded ? (\n <ChevronDown className=\"h-4 w-4 text-muted-foreground\" />\n ) : (\n <ChevronRight className=\"h-4 w-4 text-muted-foreground\" />\n )}\n </button>\n\n {toolsExpanded && (\n <div className=\"mt-4 space-y-4\">\n {Object.entries(toolsByModule).map(([module, moduleTools]) => (\n <div key={module} className=\"space-y-2\">\n <h3 className=\"text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n {module}\n </h3>\n <div className=\"space-y-1\">\n {moduleTools.map((tool) => (\n <div key={tool.name} className=\"pl-2 border-l-2 border-muted py-1\">\n <p className=\"text-sm font-medium\">{tool.name}</p>\n <p className=\"text-xs text-muted-foreground\">{tool.description}</p>\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n </div>\n )\n}\n\nexport function AiAssistantSettingsPageClient() {\n return (\n <CommandPaletteProvider tenantId=\"\" organizationId={null}>\n <AiAssistantSettingsContent />\n <CommandPalette />\n </CommandPaletteProvider>\n )\n}\n\nexport default AiAssistantSettingsPageClient\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }