refactor: Address PR comments
- Extract tool results rendering into separate ToolResults component - Hoist checkContentCompatibility function to module level following codebase conventions - Add ajv@6.12.6 as direct dependency to client package.json - All tests pass and linting is clean 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
5a628c7a00
commit
d8a2821344
5 changed files with 229 additions and 231 deletions
|
|
@ -25,6 +25,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/sdk": "^1.11.5",
|
"@modelcontextprotocol/sdk": "^1.11.5",
|
||||||
"@radix-ui/react-checkbox": "^1.1.4",
|
"@radix-ui/react-checkbox": "^1.1.4",
|
||||||
|
"ajv": "^6.12.6",
|
||||||
"@radix-ui/react-dialog": "^1.1.3",
|
"@radix-ui/react-dialog": "^1.1.3",
|
||||||
"@radix-ui/react-icons": "^1.3.0",
|
"@radix-ui/react-icons": "^1.3.0",
|
||||||
"@radix-ui/react-label": "^2.1.0",
|
"@radix-ui/react-label": "^2.1.0",
|
||||||
|
|
|
||||||
221
client/src/components/ToolResults.tsx
Normal file
221
client/src/components/ToolResults.tsx
Normal file
|
|
@ -0,0 +1,221 @@
|
||||||
|
import JsonView from "./JsonView";
|
||||||
|
import {
|
||||||
|
CallToolResultSchema,
|
||||||
|
CompatibilityCallToolResult,
|
||||||
|
Tool,
|
||||||
|
} from "@modelcontextprotocol/sdk/types.js";
|
||||||
|
import { validateToolOutput, hasOutputSchema } from "@/utils/schemaUtils";
|
||||||
|
|
||||||
|
interface ToolResultsProps {
|
||||||
|
toolResult: CompatibilityCallToolResult | null;
|
||||||
|
selectedTool: Tool | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkContentCompatibility = (
|
||||||
|
structuredContent: unknown,
|
||||||
|
unstructuredContent: Array<{
|
||||||
|
type: string;
|
||||||
|
text?: string;
|
||||||
|
[key: string]: unknown;
|
||||||
|
}>,
|
||||||
|
): { isCompatible: boolean; message: string } => {
|
||||||
|
if (
|
||||||
|
unstructuredContent.length !== 1 ||
|
||||||
|
unstructuredContent[0].type !== "text"
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
isCompatible: false,
|
||||||
|
message: "Unstructured content is not a single text block",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const textContent = unstructuredContent[0].text;
|
||||||
|
if (!textContent) {
|
||||||
|
return {
|
||||||
|
isCompatible: false,
|
||||||
|
message: "Text content is empty",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const parsedContent = JSON.parse(textContent);
|
||||||
|
const isEqual =
|
||||||
|
JSON.stringify(parsedContent) === JSON.stringify(structuredContent);
|
||||||
|
|
||||||
|
if (isEqual) {
|
||||||
|
return {
|
||||||
|
isCompatible: true,
|
||||||
|
message: "Unstructured content matches structured content",
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
isCompatible: false,
|
||||||
|
message: "Parsed JSON does not match structured content",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return {
|
||||||
|
isCompatible: false,
|
||||||
|
message: "Unstructured content is not valid JSON",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const ToolResults = ({ toolResult, selectedTool }: ToolResultsProps) => {
|
||||||
|
if (!toolResult) return null;
|
||||||
|
|
||||||
|
if ("content" in toolResult) {
|
||||||
|
const parsedResult = CallToolResultSchema.safeParse(toolResult);
|
||||||
|
if (!parsedResult.success) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h4 className="font-semibold mb-2">Invalid Tool Result:</h4>
|
||||||
|
<JsonView data={toolResult} />
|
||||||
|
<h4 className="font-semibold mb-2">Errors:</h4>
|
||||||
|
{parsedResult.error.errors.map((error, idx) => (
|
||||||
|
<JsonView data={error} key={idx} />
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const structuredResult = parsedResult.data;
|
||||||
|
const isError = structuredResult.isError ?? false;
|
||||||
|
|
||||||
|
let validationResult = null;
|
||||||
|
const toolHasOutputSchema =
|
||||||
|
selectedTool && hasOutputSchema(selectedTool.name);
|
||||||
|
|
||||||
|
if (toolHasOutputSchema) {
|
||||||
|
if (!structuredResult.structuredContent && !isError) {
|
||||||
|
validationResult = {
|
||||||
|
isValid: false,
|
||||||
|
error:
|
||||||
|
"Tool has an output schema but did not return structured content",
|
||||||
|
};
|
||||||
|
} else if (structuredResult.structuredContent) {
|
||||||
|
validationResult = validateToolOutput(
|
||||||
|
selectedTool.name,
|
||||||
|
structuredResult.structuredContent,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let compatibilityResult = null;
|
||||||
|
if (
|
||||||
|
structuredResult.structuredContent &&
|
||||||
|
structuredResult.content.length > 0 &&
|
||||||
|
selectedTool &&
|
||||||
|
hasOutputSchema(selectedTool.name)
|
||||||
|
) {
|
||||||
|
compatibilityResult = checkContentCompatibility(
|
||||||
|
structuredResult.structuredContent,
|
||||||
|
structuredResult.content,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h4 className="font-semibold mb-2">
|
||||||
|
Tool Result:{" "}
|
||||||
|
{isError ? (
|
||||||
|
<span className="text-red-600 font-semibold">Error</span>
|
||||||
|
) : (
|
||||||
|
<span className="text-green-600 font-semibold">Success</span>
|
||||||
|
)}
|
||||||
|
</h4>
|
||||||
|
{structuredResult.structuredContent && (
|
||||||
|
<div className="mb-4">
|
||||||
|
<h5 className="font-semibold mb-2 text-sm">Structured Content:</h5>
|
||||||
|
<div className="bg-gray-50 dark:bg-gray-900 p-3 rounded-lg">
|
||||||
|
<JsonView data={structuredResult.structuredContent} />
|
||||||
|
{validationResult && (
|
||||||
|
<div
|
||||||
|
className={`mt-2 p-2 rounded text-sm ${
|
||||||
|
validationResult.isValid
|
||||||
|
? "bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200"
|
||||||
|
: "bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{validationResult.isValid ? (
|
||||||
|
"✓ Valid according to output schema"
|
||||||
|
) : (
|
||||||
|
<>✗ Validation Error: {validationResult.error}</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{!structuredResult.structuredContent &&
|
||||||
|
validationResult &&
|
||||||
|
!validationResult.isValid && (
|
||||||
|
<div className="mb-4">
|
||||||
|
<div className="bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200 p-2 rounded text-sm">
|
||||||
|
✗ Validation Error: {validationResult.error}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{structuredResult.content.length > 0 && (
|
||||||
|
<div className="mb-4">
|
||||||
|
{structuredResult.structuredContent && (
|
||||||
|
<>
|
||||||
|
<h5 className="font-semibold mb-2 text-sm">
|
||||||
|
Unstructured Content:
|
||||||
|
</h5>
|
||||||
|
{compatibilityResult && (
|
||||||
|
<div
|
||||||
|
className={`mb-2 p-2 rounded text-sm ${
|
||||||
|
compatibilityResult.isCompatible
|
||||||
|
? "bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200"
|
||||||
|
: "bg-yellow-100 dark:bg-yellow-900 text-yellow-800 dark:text-yellow-200"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{compatibilityResult.isCompatible ? "✓" : "⚠"}{" "}
|
||||||
|
{compatibilityResult.message}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{structuredResult.content.map((item, index) => (
|
||||||
|
<div key={index} className="mb-2">
|
||||||
|
{item.type === "text" && (
|
||||||
|
<JsonView data={item.text} isError={isError} />
|
||||||
|
)}
|
||||||
|
{item.type === "image" && (
|
||||||
|
<img
|
||||||
|
src={`data:${item.mimeType};base64,${item.data}`}
|
||||||
|
alt="Tool result image"
|
||||||
|
className="max-w-full h-auto"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{item.type === "resource" &&
|
||||||
|
(item.resource?.mimeType?.startsWith("audio/") ? (
|
||||||
|
<audio
|
||||||
|
controls
|
||||||
|
src={`data:${item.resource.mimeType};base64,${item.resource.blob}`}
|
||||||
|
className="w-full"
|
||||||
|
>
|
||||||
|
<p>Your browser does not support audio playback</p>
|
||||||
|
</audio>
|
||||||
|
) : (
|
||||||
|
<JsonView data={item.resource} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
} else if ("toolResult" in toolResult) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h4 className="font-semibold mb-2">Tool Result (Legacy):</h4>
|
||||||
|
<JsonView data={toolResult.toolResult} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ToolResults;
|
||||||
|
|
@ -7,13 +7,8 @@ import { TabsContent } from "@/components/ui/tabs";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
import DynamicJsonForm from "./DynamicJsonForm";
|
import DynamicJsonForm from "./DynamicJsonForm";
|
||||||
import type { JsonValue, JsonSchemaType } from "@/utils/jsonUtils";
|
import type { JsonValue, JsonSchemaType } from "@/utils/jsonUtils";
|
||||||
|
import { generateDefaultValue } from "@/utils/schemaUtils";
|
||||||
import {
|
import {
|
||||||
generateDefaultValue,
|
|
||||||
validateToolOutput,
|
|
||||||
hasOutputSchema,
|
|
||||||
} from "@/utils/schemaUtils";
|
|
||||||
import {
|
|
||||||
CallToolResultSchema,
|
|
||||||
CompatibilityCallToolResult,
|
CompatibilityCallToolResult,
|
||||||
ListToolsResult,
|
ListToolsResult,
|
||||||
Tool,
|
Tool,
|
||||||
|
|
@ -22,6 +17,7 @@ import { Loader2, Send, ChevronDown, ChevronUp } from "lucide-react";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import ListPane from "./ListPane";
|
import ListPane from "./ListPane";
|
||||||
import JsonView from "./JsonView";
|
import JsonView from "./JsonView";
|
||||||
|
import ToolResults from "./ToolResults";
|
||||||
|
|
||||||
const ToolsTab = ({
|
const ToolsTab = ({
|
||||||
tools,
|
tools,
|
||||||
|
|
@ -57,224 +53,6 @@ const ToolsTab = ({
|
||||||
setParams(Object.fromEntries(params));
|
setParams(Object.fromEntries(params));
|
||||||
}, [selectedTool]);
|
}, [selectedTool]);
|
||||||
|
|
||||||
// Check compatibility between structured and unstructured content
|
|
||||||
const checkContentCompatibility = (
|
|
||||||
structuredContent: unknown,
|
|
||||||
unstructuredContent: Array<{
|
|
||||||
type: string;
|
|
||||||
text?: string;
|
|
||||||
[key: string]: unknown;
|
|
||||||
}>,
|
|
||||||
): { isCompatible: boolean; message: string } => {
|
|
||||||
// Check if unstructured content is a single text block
|
|
||||||
if (
|
|
||||||
unstructuredContent.length !== 1 ||
|
|
||||||
unstructuredContent[0].type !== "text"
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
isCompatible: false,
|
|
||||||
message: "Unstructured content is not a single text block",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const textContent = unstructuredContent[0].text;
|
|
||||||
if (!textContent) {
|
|
||||||
return {
|
|
||||||
isCompatible: false,
|
|
||||||
message: "Text content is empty",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Try to parse the text as JSON
|
|
||||||
const parsedContent = JSON.parse(textContent);
|
|
||||||
|
|
||||||
// Deep equality check
|
|
||||||
const isEqual =
|
|
||||||
JSON.stringify(parsedContent) === JSON.stringify(structuredContent);
|
|
||||||
|
|
||||||
if (isEqual) {
|
|
||||||
return {
|
|
||||||
isCompatible: true,
|
|
||||||
message: "Unstructured content matches structured content",
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
isCompatible: false,
|
|
||||||
message: "Parsed JSON does not match structured content",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
return {
|
|
||||||
isCompatible: false,
|
|
||||||
message: "Unstructured content is not valid JSON",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderToolResult = () => {
|
|
||||||
if (!toolResult) return null;
|
|
||||||
|
|
||||||
if ("content" in toolResult) {
|
|
||||||
const parsedResult = CallToolResultSchema.safeParse(toolResult);
|
|
||||||
if (!parsedResult.success) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<h4 className="font-semibold mb-2">Invalid Tool Result:</h4>
|
|
||||||
<JsonView data={toolResult} />
|
|
||||||
<h4 className="font-semibold mb-2">Errors:</h4>
|
|
||||||
{parsedResult.error.errors.map((error, idx) => (
|
|
||||||
<JsonView data={error} key={idx} />
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const structuredResult = parsedResult.data;
|
|
||||||
const isError = structuredResult.isError ?? false;
|
|
||||||
|
|
||||||
// Validate structured content if present and tool has output schema
|
|
||||||
let validationResult = null;
|
|
||||||
const toolHasOutputSchema =
|
|
||||||
selectedTool && hasOutputSchema(selectedTool.name);
|
|
||||||
|
|
||||||
if (toolHasOutputSchema) {
|
|
||||||
if (!structuredResult.structuredContent && !isError) {
|
|
||||||
// Tool has output schema but didn't return structured content (and it's not an error)
|
|
||||||
validationResult = {
|
|
||||||
isValid: false,
|
|
||||||
error:
|
|
||||||
"Tool has an output schema but did not return structured content",
|
|
||||||
};
|
|
||||||
} else if (structuredResult.structuredContent) {
|
|
||||||
// Validate the structured content
|
|
||||||
validationResult = validateToolOutput(
|
|
||||||
selectedTool.name,
|
|
||||||
structuredResult.structuredContent,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check compatibility if both structured and unstructured content exist
|
|
||||||
// AND the tool has an output schema
|
|
||||||
let compatibilityResult = null;
|
|
||||||
if (
|
|
||||||
structuredResult.structuredContent &&
|
|
||||||
structuredResult.content.length > 0 &&
|
|
||||||
selectedTool &&
|
|
||||||
hasOutputSchema(selectedTool.name)
|
|
||||||
) {
|
|
||||||
compatibilityResult = checkContentCompatibility(
|
|
||||||
structuredResult.structuredContent,
|
|
||||||
structuredResult.content,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<h4 className="font-semibold mb-2">
|
|
||||||
Tool Result:{" "}
|
|
||||||
{isError ? (
|
|
||||||
<span className="text-red-600 font-semibold">Error</span>
|
|
||||||
) : (
|
|
||||||
<span className="text-green-600 font-semibold">Success</span>
|
|
||||||
)}
|
|
||||||
</h4>
|
|
||||||
{structuredResult.structuredContent && (
|
|
||||||
<div className="mb-4">
|
|
||||||
<h5 className="font-semibold mb-2 text-sm">
|
|
||||||
Structured Content:
|
|
||||||
</h5>
|
|
||||||
<div className="bg-gray-50 dark:bg-gray-900 p-3 rounded-lg">
|
|
||||||
<JsonView data={structuredResult.structuredContent} />
|
|
||||||
{validationResult && (
|
|
||||||
<div
|
|
||||||
className={`mt-2 p-2 rounded text-sm ${
|
|
||||||
validationResult.isValid
|
|
||||||
? "bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200"
|
|
||||||
: "bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{validationResult.isValid ? (
|
|
||||||
"✓ Valid according to output schema"
|
|
||||||
) : (
|
|
||||||
<>✗ Validation Error: {validationResult.error}</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{!structuredResult.structuredContent &&
|
|
||||||
validationResult &&
|
|
||||||
!validationResult.isValid && (
|
|
||||||
<div className="mb-4">
|
|
||||||
<div className="bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200 p-2 rounded text-sm">
|
|
||||||
✗ Validation Error: {validationResult.error}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{structuredResult.content.length > 0 && (
|
|
||||||
<div className="mb-4">
|
|
||||||
{structuredResult.structuredContent && (
|
|
||||||
<>
|
|
||||||
<h5 className="font-semibold mb-2 text-sm">
|
|
||||||
Unstructured Content:
|
|
||||||
</h5>
|
|
||||||
{compatibilityResult && (
|
|
||||||
<div
|
|
||||||
className={`mb-2 p-2 rounded text-sm ${
|
|
||||||
compatibilityResult.isCompatible
|
|
||||||
? "bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200"
|
|
||||||
: "bg-yellow-100 dark:bg-yellow-900 text-yellow-800 dark:text-yellow-200"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{compatibilityResult.isCompatible ? "✓" : "⚠"}{" "}
|
|
||||||
{compatibilityResult.message}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{structuredResult.content.map((item, index) => (
|
|
||||||
<div key={index} className="mb-2">
|
|
||||||
{item.type === "text" && (
|
|
||||||
<JsonView data={item.text} isError={isError} />
|
|
||||||
)}
|
|
||||||
{item.type === "image" && (
|
|
||||||
<img
|
|
||||||
src={`data:${item.mimeType};base64,${item.data}`}
|
|
||||||
alt="Tool result image"
|
|
||||||
className="max-w-full h-auto"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{item.type === "resource" &&
|
|
||||||
(item.resource?.mimeType?.startsWith("audio/") ? (
|
|
||||||
<audio
|
|
||||||
controls
|
|
||||||
src={`data:${item.resource.mimeType};base64,${item.resource.blob}`}
|
|
||||||
className="w-full"
|
|
||||||
>
|
|
||||||
<p>Your browser does not support audio playback</p>
|
|
||||||
</audio>
|
|
||||||
) : (
|
|
||||||
<JsonView data={item.resource} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
} else if ("toolResult" in toolResult) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<h4 className="font-semibold mb-2">Tool Result (Legacy):</h4>
|
|
||||||
|
|
||||||
<JsonView data={toolResult.toolResult} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TabsContent value="tools">
|
<TabsContent value="tools">
|
||||||
<div className="grid grid-cols-2 gap-4">
|
<div className="grid grid-cols-2 gap-4">
|
||||||
|
|
@ -475,7 +253,10 @@ const ToolsTab = ({
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
{toolResult && renderToolResult()}
|
<ToolResults
|
||||||
|
toolResult={toolResult}
|
||||||
|
selectedTool={selectedTool}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<Alert>
|
<Alert>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import Ajv from "ajv";
|
||||||
import type { ValidateFunction } from "ajv";
|
import type { ValidateFunction } from "ajv";
|
||||||
import type { Tool } from "@modelcontextprotocol/sdk/types.js";
|
import type { Tool } from "@modelcontextprotocol/sdk/types.js";
|
||||||
|
|
||||||
// Create a single Ajv instance following the SDK pattern
|
|
||||||
const ajv = new Ajv();
|
const ajv = new Ajv();
|
||||||
|
|
||||||
// Cache for compiled validators
|
// Cache for compiled validators
|
||||||
|
|
|
||||||
6
package-lock.json
generated
6
package-lock.json
generated
|
|
@ -77,6 +77,7 @@
|
||||||
"@radix-ui/react-tabs": "^1.1.1",
|
"@radix-ui/react-tabs": "^1.1.1",
|
||||||
"@radix-ui/react-toast": "^1.2.6",
|
"@radix-ui/react-toast": "^1.2.6",
|
||||||
"@radix-ui/react-tooltip": "^1.1.8",
|
"@radix-ui/react-tooltip": "^1.1.8",
|
||||||
|
"ajv": "^6.12.6",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "^1.0.4",
|
"cmdk": "^1.0.4",
|
||||||
|
|
@ -4002,7 +4003,6 @@
|
||||||
"version": "6.12.6",
|
"version": "6.12.6",
|
||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fast-deep-equal": "^3.1.1",
|
"fast-deep-equal": "^3.1.1",
|
||||||
|
|
@ -5710,7 +5710,6 @@
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
||||||
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
|
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/fast-levenshtein": {
|
"node_modules/fast-levenshtein": {
|
||||||
|
|
@ -7740,7 +7739,6 @@
|
||||||
"version": "0.4.1",
|
"version": "0.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/json-stable-stringify-without-jsonify": {
|
"node_modules/json-stable-stringify-without-jsonify": {
|
||||||
|
|
@ -8812,7 +8810,6 @@
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||||
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
|
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
|
|
@ -10488,7 +10485,6 @@
|
||||||
"version": "4.4.1",
|
"version": "4.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||||
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
|
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
|
||||||
"dev": true,
|
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"punycode": "^2.1.0"
|
"punycode": "^2.1.0"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue