@open-mercato/ai-assistant 0.6.4-develop.4339.1.fad812f76f → 0.6.4-develop.4358.1.233d5675c7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/modules/ai_assistant/components/McpConfigDialog.js +2 -10
- package/dist/modules/ai_assistant/components/McpConfigDialog.js.map +2 -2
- package/dist/modules/ai_assistant/components/SessionKeyDialog.js +2 -9
- package/dist/modules/ai_assistant/components/SessionKeyDialog.js.map +2 -2
- package/package.json +6 -6
- package/src/modules/ai_assistant/components/McpConfigDialog.tsx +3 -10
- package/src/modules/ai_assistant/components/SessionKeyDialog.tsx +3 -10
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import * as React from "react";
|
|
4
3
|
import { useState } from "react";
|
|
5
4
|
import { Copy, RefreshCw, AlertTriangle, Check, Settings } from "lucide-react";
|
|
6
5
|
import {
|
|
@@ -14,6 +13,7 @@ import {
|
|
|
14
13
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
15
14
|
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
16
15
|
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
16
|
+
import { useDialogKeyHandler } from "@open-mercato/ui/hooks/useDialogKeyHandler";
|
|
17
17
|
function McpConfigDialog({ open, onOpenChange, mcpUrl }) {
|
|
18
18
|
const t = useT();
|
|
19
19
|
const [apiKey, setApiKey] = useState(null);
|
|
@@ -67,15 +67,6 @@ function McpConfigDialog({ open, onOpenChange, mcpUrl }) {
|
|
|
67
67
|
setTimeout(() => setCopiedKey(false), 2e3);
|
|
68
68
|
}
|
|
69
69
|
};
|
|
70
|
-
const handleKeyDown = React.useCallback(
|
|
71
|
-
(event) => {
|
|
72
|
-
if (event.key === "Escape") {
|
|
73
|
-
event.preventDefault();
|
|
74
|
-
onOpenChange(false);
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
[onOpenChange]
|
|
78
|
-
);
|
|
79
70
|
const handleClose = () => {
|
|
80
71
|
setApiKey(null);
|
|
81
72
|
setError(null);
|
|
@@ -83,6 +74,7 @@ function McpConfigDialog({ open, onOpenChange, mcpUrl }) {
|
|
|
83
74
|
setCopiedKey(false);
|
|
84
75
|
onOpenChange(false);
|
|
85
76
|
};
|
|
77
|
+
const handleKeyDown = useDialogKeyHandler({ onCancel: handleClose });
|
|
86
78
|
return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(DialogContent, { onKeyDown: handleKeyDown, className: "sm:max-w-2xl", children: [
|
|
87
79
|
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
88
80
|
/* @__PURE__ */ jsxs(DialogTitle, { className: "flex items-center gap-2", 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
|
|
5
|
-
"mappings": ";
|
|
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'\nimport { useDialogKeyHandler } from '@open-mercato/ui/hooks/useDialogKeyHandler'\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 handleClose = () => {\n setApiKey(null)\n setError(null)\n setCopiedConfig(false)\n setCopiedKey(false)\n onOpenChange(false)\n }\n\n const handleKeyDown = useDialogKeyHandler({ onCancel: handleClose })\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
|
}
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
15
15
|
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
16
16
|
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
17
|
+
import { useDialogKeyHandler } from "@open-mercato/ui/hooks/useDialogKeyHandler";
|
|
17
18
|
function SessionKeyDialog({ open, onOpenChange }) {
|
|
18
19
|
const t = useT();
|
|
19
20
|
const [sessionToken, setSessionToken] = useState(null);
|
|
@@ -71,15 +72,6 @@ Workflow (use this order):
|
|
|
71
72
|
setCopiedInstructions(true);
|
|
72
73
|
setTimeout(() => setCopiedInstructions(false), 2e3);
|
|
73
74
|
};
|
|
74
|
-
const handleKeyDown = React.useCallback(
|
|
75
|
-
(event) => {
|
|
76
|
-
if (event.key === "Escape") {
|
|
77
|
-
event.preventDefault();
|
|
78
|
-
onOpenChange(false);
|
|
79
|
-
}
|
|
80
|
-
},
|
|
81
|
-
[onOpenChange]
|
|
82
|
-
);
|
|
83
75
|
const handleClose = () => {
|
|
84
76
|
setSessionToken(null);
|
|
85
77
|
setExpiresAt(null);
|
|
@@ -88,6 +80,7 @@ Workflow (use this order):
|
|
|
88
80
|
setCopiedInstructions(false);
|
|
89
81
|
onOpenChange(false);
|
|
90
82
|
};
|
|
83
|
+
const handleKeyDown = useDialogKeyHandler({ onCancel: handleClose });
|
|
91
84
|
const formatExpiry = (isoDate) => {
|
|
92
85
|
if (!isoDate) return t("ai_assistant.session.expiresDefault");
|
|
93
86
|
const date = new Date(isoDate);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/ai_assistant/components/SessionKeyDialog.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useState } from 'react'\nimport { Copy, RefreshCw, AlertTriangle, Check, Key, Clock } 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}\n\ntype SessionKeyResponse = {\n sessionToken: string\n expiresAt: string\n}\n\nexport default function SessionKeyDialog({ open, onOpenChange }: Props) {\n const t = useT()\n const [sessionToken, setSessionToken] = useState<string | null>(null)\n const [expiresAt, setExpiresAt] = useState<string | null>(null)\n const [isGenerating, setIsGenerating] = useState(false)\n const [copiedToken, setCopiedToken] = useState(false)\n const [copiedInstructions, setCopiedInstructions] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const generateSessionKey = async () => {\n setIsGenerating(true)\n setError(null)\n try {\n const res = await apiCall<SessionKeyResponse>('/api/ai_assistant/session-key', {\n method: 'POST',\n })\n if (res.ok && res.result?.sessionToken) {\n setSessionToken(res.result.sessionToken)\n setExpiresAt(res.result.expiresAt)\n } else {\n setError(t('ai_assistant.session.error.failed'))\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : t('ai_assistant.session.error.failed'))\n } finally {\n setIsGenerating(false)\n }\n }\n\n // Auto-generate on open if no token\n React.useEffect(() => {\n if (open && !sessionToken && !isGenerating) {\n generateSessionKey()\n }\n }, [open])\n\n const llmInstructions = `You have access to Open Mercato MCP tools for managing business data (customers, orders, products, etc.).\n\nIMPORTANT: Include \"_sessionToken\" in EVERY tool call:\n{\n \"_sessionToken\": \"${sessionToken || 'sess_abc123...'}\",\n ...other parameters\n}\n\nWorkflow (use this order):\n1. \"discover_schema\" - Understand entities, fields, and relationships first\n Examples: { \"query\": \"customer\" }, { \"query\": \"orders\" }, { \"query\": \"products\" }\n2. \"find_api\" - Find the API endpoint for your operation (list, get, create, update, delete)\n3. \"call_api\" - Execute the API call with proper parameters`\n\n const copyToken = async () => {\n if (sessionToken) {\n await navigator.clipboard.writeText(sessionToken)\n setCopiedToken(true)\n setTimeout(() => setCopiedToken(false), 2000)\n }\n }\n\n const copyInstructions = async () => {\n await navigator.clipboard.writeText(llmInstructions)\n setCopiedInstructions(true)\n setTimeout(() => setCopiedInstructions(false), 2000)\n }\n\n const
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useState } from 'react'\nimport { Copy, RefreshCw, AlertTriangle, Check, Key, Clock } 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'\nimport { useDialogKeyHandler } from '@open-mercato/ui/hooks/useDialogKeyHandler'\n\ntype Props = {\n open: boolean\n onOpenChange: (next: boolean) => void\n}\n\ntype SessionKeyResponse = {\n sessionToken: string\n expiresAt: string\n}\n\nexport default function SessionKeyDialog({ open, onOpenChange }: Props) {\n const t = useT()\n const [sessionToken, setSessionToken] = useState<string | null>(null)\n const [expiresAt, setExpiresAt] = useState<string | null>(null)\n const [isGenerating, setIsGenerating] = useState(false)\n const [copiedToken, setCopiedToken] = useState(false)\n const [copiedInstructions, setCopiedInstructions] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const generateSessionKey = async () => {\n setIsGenerating(true)\n setError(null)\n try {\n const res = await apiCall<SessionKeyResponse>('/api/ai_assistant/session-key', {\n method: 'POST',\n })\n if (res.ok && res.result?.sessionToken) {\n setSessionToken(res.result.sessionToken)\n setExpiresAt(res.result.expiresAt)\n } else {\n setError(t('ai_assistant.session.error.failed'))\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : t('ai_assistant.session.error.failed'))\n } finally {\n setIsGenerating(false)\n }\n }\n\n // Auto-generate on open if no token\n React.useEffect(() => {\n if (open && !sessionToken && !isGenerating) {\n generateSessionKey()\n }\n }, [open])\n\n const llmInstructions = `You have access to Open Mercato MCP tools for managing business data (customers, orders, products, etc.).\n\nIMPORTANT: Include \"_sessionToken\" in EVERY tool call:\n{\n \"_sessionToken\": \"${sessionToken || 'sess_abc123...'}\",\n ...other parameters\n}\n\nWorkflow (use this order):\n1. \"discover_schema\" - Understand entities, fields, and relationships first\n Examples: { \"query\": \"customer\" }, { \"query\": \"orders\" }, { \"query\": \"products\" }\n2. \"find_api\" - Find the API endpoint for your operation (list, get, create, update, delete)\n3. \"call_api\" - Execute the API call with proper parameters`\n\n const copyToken = async () => {\n if (sessionToken) {\n await navigator.clipboard.writeText(sessionToken)\n setCopiedToken(true)\n setTimeout(() => setCopiedToken(false), 2000)\n }\n }\n\n const copyInstructions = async () => {\n await navigator.clipboard.writeText(llmInstructions)\n setCopiedInstructions(true)\n setTimeout(() => setCopiedInstructions(false), 2000)\n }\n\n const handleClose = () => {\n setSessionToken(null)\n setExpiresAt(null)\n setError(null)\n setCopiedToken(false)\n setCopiedInstructions(false)\n onOpenChange(false)\n }\n\n const handleKeyDown = useDialogKeyHandler({ onCancel: handleClose })\n\n const formatExpiry = (isoDate: string | null) => {\n if (!isoDate) return t('ai_assistant.session.expiresDefault')\n const date = new Date(isoDate)\n return date.toLocaleString()\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 <Key className=\"h-5 w-5\" />\n {t('ai_assistant.session.title')}\n </DialogTitle>\n <DialogDescription>\n {t('ai_assistant.session.description')}\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-4\">\n {isGenerating && !sessionToken ? (\n <div className=\"flex items-center justify-center py-8 text-muted-foreground\">\n <RefreshCw className=\"h-5 w-5 animate-spin mr-2\" />\n {t('ai_assistant.session.generating')}\n </div>\n ) : sessionToken ? (\n <>\n {/* Session Token */}\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-sm font-medium\">{t('ai_assistant.session.tokenLabel')}</span>\n <Button variant=\"outline\" size=\"sm\" onClick={copyToken} className=\"gap-1.5\">\n {copiedToken ? <Check className=\"h-3.5 w-3.5\" /> : <Copy className=\"h-3.5 w-3.5\" />}\n {copiedToken ? t('ai_assistant.session.copied') : t('ai_assistant.session.copy')}\n </Button>\n </div>\n <code className=\"block text-xs bg-muted px-3 py-2 rounded font-mono break-all\">\n {sessionToken}\n </code>\n </div>\n\n {/* Expiry Info */}\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Clock className=\"h-4 w-4\" />\n <span>{t('ai_assistant.session.expires')} {formatExpiry(expiresAt)}</span>\n </div>\n\n {/* Separator */}\n <div className=\"border-t\" />\n\n {/* LLM Instructions */}\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-sm font-medium\">{t('ai_assistant.session.llmInstructions')}</span>\n <Button variant=\"outline\" size=\"sm\" onClick={copyInstructions} className=\"gap-1.5\">\n {copiedInstructions ? <Check className=\"h-3.5 w-3.5\" /> : <Copy className=\"h-3.5 w-3.5\" />}\n {copiedInstructions ? t('ai_assistant.session.copied') : t('ai_assistant.session.copy')}\n </Button>\n </div>\n <p className=\"text-xs text-muted-foreground\">\n {t('ai_assistant.session.copyToSystemPrompt')}\n </p>\n <pre className=\"bg-muted/50 rounded-lg p-4 text-xs font-mono overflow-x-auto border whitespace-pre-wrap\">\n {llmInstructions}\n </pre>\n </div>\n </>\n ) : null}\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 </div>\n\n <DialogFooter>\n {sessionToken && (\n <Button\n variant=\"outline\"\n onClick={generateSessionKey}\n disabled={isGenerating}\n className=\"gap-1.5\"\n >\n <RefreshCw className={`h-4 w-4 ${isGenerating ? 'animate-spin' : ''}`} />\n {t('ai_assistant.session.generateNew')}\n </Button>\n )}\n <Button variant=\"outline\" onClick={handleClose}>\n {t('ai_assistant.session.close')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/ai-assistant",
|
|
3
|
-
"version": "0.6.4-develop.
|
|
3
|
+
"version": "0.6.4-develop.4358.1.233d5675c7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22.0.0"
|
|
@@ -98,16 +98,16 @@
|
|
|
98
98
|
"zod-to-json-schema": "^3.25.2"
|
|
99
99
|
},
|
|
100
100
|
"peerDependencies": {
|
|
101
|
-
"@open-mercato/shared": "0.6.4-develop.
|
|
102
|
-
"@open-mercato/ui": "0.6.4-develop.
|
|
101
|
+
"@open-mercato/shared": "0.6.4-develop.4358.1.233d5675c7",
|
|
102
|
+
"@open-mercato/ui": "0.6.4-develop.4358.1.233d5675c7",
|
|
103
103
|
"react": "^19.0.0",
|
|
104
104
|
"react-dom": "^19.0.0",
|
|
105
105
|
"zod": ">=3.23.0"
|
|
106
106
|
},
|
|
107
107
|
"devDependencies": {
|
|
108
|
-
"@open-mercato/cli": "0.6.4-develop.
|
|
109
|
-
"@open-mercato/shared": "0.6.4-develop.
|
|
110
|
-
"@open-mercato/ui": "0.6.4-develop.
|
|
108
|
+
"@open-mercato/cli": "0.6.4-develop.4358.1.233d5675c7",
|
|
109
|
+
"@open-mercato/shared": "0.6.4-develop.4358.1.233d5675c7",
|
|
110
|
+
"@open-mercato/ui": "0.6.4-develop.4358.1.233d5675c7",
|
|
111
111
|
"@types/react": "^19.2.16",
|
|
112
112
|
"@types/react-dom": "^19.2.3",
|
|
113
113
|
"react": "19.2.7",
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
15
15
|
import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
|
|
16
16
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
17
|
+
import { useDialogKeyHandler } from '@open-mercato/ui/hooks/useDialogKeyHandler'
|
|
17
18
|
|
|
18
19
|
type Props = {
|
|
19
20
|
open: boolean
|
|
@@ -87,16 +88,6 @@ export default function McpConfigDialog({ open, onOpenChange, mcpUrl }: Props) {
|
|
|
87
88
|
}
|
|
88
89
|
}
|
|
89
90
|
|
|
90
|
-
const handleKeyDown = React.useCallback(
|
|
91
|
-
(event: React.KeyboardEvent) => {
|
|
92
|
-
if (event.key === 'Escape') {
|
|
93
|
-
event.preventDefault()
|
|
94
|
-
onOpenChange(false)
|
|
95
|
-
}
|
|
96
|
-
},
|
|
97
|
-
[onOpenChange],
|
|
98
|
-
)
|
|
99
|
-
|
|
100
91
|
const handleClose = () => {
|
|
101
92
|
setApiKey(null)
|
|
102
93
|
setError(null)
|
|
@@ -105,6 +96,8 @@ export default function McpConfigDialog({ open, onOpenChange, mcpUrl }: Props) {
|
|
|
105
96
|
onOpenChange(false)
|
|
106
97
|
}
|
|
107
98
|
|
|
99
|
+
const handleKeyDown = useDialogKeyHandler({ onCancel: handleClose })
|
|
100
|
+
|
|
108
101
|
return (
|
|
109
102
|
<Dialog open={open} onOpenChange={handleClose}>
|
|
110
103
|
<DialogContent onKeyDown={handleKeyDown} className="sm:max-w-2xl">
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
15
15
|
import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
|
|
16
16
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
17
|
+
import { useDialogKeyHandler } from '@open-mercato/ui/hooks/useDialogKeyHandler'
|
|
17
18
|
|
|
18
19
|
type Props = {
|
|
19
20
|
open: boolean
|
|
@@ -89,16 +90,6 @@ Workflow (use this order):
|
|
|
89
90
|
setTimeout(() => setCopiedInstructions(false), 2000)
|
|
90
91
|
}
|
|
91
92
|
|
|
92
|
-
const handleKeyDown = React.useCallback(
|
|
93
|
-
(event: React.KeyboardEvent) => {
|
|
94
|
-
if (event.key === 'Escape') {
|
|
95
|
-
event.preventDefault()
|
|
96
|
-
onOpenChange(false)
|
|
97
|
-
}
|
|
98
|
-
},
|
|
99
|
-
[onOpenChange],
|
|
100
|
-
)
|
|
101
|
-
|
|
102
93
|
const handleClose = () => {
|
|
103
94
|
setSessionToken(null)
|
|
104
95
|
setExpiresAt(null)
|
|
@@ -108,6 +99,8 @@ Workflow (use this order):
|
|
|
108
99
|
onOpenChange(false)
|
|
109
100
|
}
|
|
110
101
|
|
|
102
|
+
const handleKeyDown = useDialogKeyHandler({ onCancel: handleClose })
|
|
103
|
+
|
|
111
104
|
const formatExpiry = (isoDate: string | null) => {
|
|
112
105
|
if (!isoDate) return t('ai_assistant.session.expiresDefault')
|
|
113
106
|
const date = new Date(isoDate)
|