From 6069b1821fe5bacccdcb837df91461a37cb2e2af Mon Sep 17 00:00:00 2001 From: GeneralJerel <85066839+GeneralJerel@users.noreply.github.com> Date: Wed, 10 Jun 2026 08:19:16 -0700 Subject: [PATCH 01/10] Phase 0+A1: test infra, CopilotKit 1.55.2-next.1, single-source design system - Add vitest (apps/app jsdom, apps/mcp node) + pytest (apps/agent) + turbo test task - Pin @copilotkit/{react-core,react-ui,runtime} to 1.55.2-next.1 (canonical OpenGenerativeUI rails: generateSandboxedUi, OpenGenerativeUIMiddleware) - New @repo/design-system package single-sources THEME_CSS / SVG_CLASSES_CSS / FORM_STYLES_CSS / importmap; apps/app and apps/mcp now consume it, killing the "keep in sync" fork in apps/mcp/src/renderer.ts (plan acceptance #4, enforced by a repo-scan test) Co-Authored-By: Claude Fable 5 --- apps/agent/pyproject.toml | 9 + apps/agent/tests/__init__.py | 0 apps/agent/tests/test_smoke.py | 7 + apps/agent/uv.lock | 51 + apps/app/package.json | 17 +- .../components/generative-ui/export-utils.ts | 22 +- .../generative-ui/plan-card.test.tsx | 23 + .../generative-ui/widget-renderer.tsx | 330 +-- apps/app/vitest.config.ts | 15 + apps/mcp/package.json | 14 +- apps/mcp/src/renderer.ts | 292 +-- apps/mcp/tests/skills.test.ts | 10 + apps/mcp/vitest.config.ts | 7 + package.json | 1 + packages/design-system/.gitignore | 3 + packages/design-system/package.json | 26 + .../src/__tests__/design-system.test.ts | 70 + .../src/__tests__/single-source.test.ts | 35 + packages/design-system/src/index.ts | 451 ++++ packages/design-system/tsconfig.json | 14 + packages/design-system/vitest.config.ts | 7 + pnpm-lock.yaml | 2028 ++++++++++++++--- pnpm-workspace.yaml | 1 + turbo.json | 3 + 24 files changed, 2491 insertions(+), 945 deletions(-) create mode 100644 apps/agent/tests/__init__.py create mode 100644 apps/agent/tests/test_smoke.py create mode 100644 apps/app/src/components/generative-ui/plan-card.test.tsx create mode 100644 apps/app/vitest.config.ts create mode 100644 apps/mcp/tests/skills.test.ts create mode 100644 apps/mcp/vitest.config.ts create mode 100644 packages/design-system/.gitignore create mode 100644 packages/design-system/package.json create mode 100644 packages/design-system/src/__tests__/design-system.test.ts create mode 100644 packages/design-system/src/__tests__/single-source.test.ts create mode 100644 packages/design-system/src/index.ts create mode 100644 packages/design-system/tsconfig.json create mode 100644 packages/design-system/vitest.config.ts diff --git a/apps/agent/pyproject.toml b/apps/agent/pyproject.toml index ad334a9..4bb0498 100644 --- a/apps/agent/pyproject.toml +++ b/apps/agent/pyproject.toml @@ -17,3 +17,12 @@ dependencies = [ "langchain-mcp-adapters>=0.2.1", "deepagents>=0.1.0", ] + +[dependency-groups] +dev = [ + "pytest>=9.0.3", +] + +[tool.pytest.ini_options] +testpaths = ["tests"] +pythonpath = ["."] diff --git a/apps/agent/tests/__init__.py b/apps/agent/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/agent/tests/test_smoke.py b/apps/agent/tests/test_smoke.py new file mode 100644 index 0000000..bb2df11 --- /dev/null +++ b/apps/agent/tests/test_smoke.py @@ -0,0 +1,7 @@ +"""Smoke test proving the pytest harness runs against real agent code.""" + +from src.plan import plan_visualization + + +def test_plan_visualization_is_a_langchain_tool(): + assert plan_visualization.name == "plan_visualization" diff --git a/apps/agent/uv.lock b/apps/agent/uv.lock index f1bf1a1..cb3775c 100644 --- a/apps/agent/uv.lock +++ b/apps/agent/uv.lock @@ -462,6 +462,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, ] +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + [[package]] name = "jiter" version = "0.12.0" @@ -897,6 +906,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8a/fb/453af21468774dbd0954853735a4fc7841544c3022ff86e5d93252d7ea72/partialjson-0.0.8-py3-none-any.whl", hash = "sha256:22c6c60944137f931a7033fa0eeee2d74b49114f3d45c25a560b07a6ebf22b76", size = 4549, upload-time = "2024-08-03T18:03:14.447Z" }, ] +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + [[package]] name = "pyasn1" version = "0.6.3" @@ -1027,6 +1045,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880, upload-time = "2025-11-10T14:25:45.546Z" }, ] +[[package]] +name = "pygments" +version = "2.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, +] + [[package]] name = "pyjwt" version = "2.10.1" @@ -1041,6 +1068,22 @@ crypto = [ { name = "cryptography" }, ] +[[package]] +name = "pytest" +version = "9.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/549bd94f1a0a402dc8cf64563a117c0f3765662e2e668477624baeec44d5/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165, upload-time = "2026-04-07T17:16:18.027Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249, upload-time = "2026-04-07T17:16:16.13Z" }, +] + [[package]] name = "python-dotenv" version = "1.2.1" @@ -1340,6 +1383,11 @@ dependencies = [ { name = "uvicorn" }, ] +[package.dev-dependencies] +dev = [ + { name = "pytest" }, +] + [package.metadata] requires-dist = [ { name = "ag-ui-langgraph", specifier = "==0.0.25" }, @@ -1356,6 +1404,9 @@ requires-dist = [ { name = "uvicorn", specifier = ">=0.29.0,<1.0.0" }, ] +[package.metadata.requires-dev] +dev = [{ name = "pytest", specifier = ">=9.0.3" }] + [[package]] name = "sniffio" version = "1.3.1" diff --git a/apps/app/package.json b/apps/app/package.json index ba21391..7728cd9 100644 --- a/apps/app/package.json +++ b/apps/app/package.json @@ -6,15 +6,17 @@ "dev": "next dev --turbopack", "build": "next build", "start": "next start", - "lint": "eslint ." + "lint": "eslint .", + "test": "vitest run" }, "dependencies": { "@ag-ui/a2ui-middleware": "^0.0.2", "@ag-ui/mcp-apps-middleware": "^0.0.3", - "@copilotkit/react-core": "next", - "@copilotkit/react-ui": "next", - "@copilotkit/runtime": "next", - "@copilotkitnext/shared": "next", + "@copilotkit/react-core": "1.55.2-next.1", + "@copilotkit/react-ui": "1.55.2-next.1", + "@copilotkit/runtime": "1.55.2-next.1", + "@copilotkitnext/shared": "1.54.1-next.6", + "@repo/design-system": "workspace:*", "next": "16.1.6", "qrcode.react": "^4.2.0", "react": "^19.2.4", @@ -26,13 +28,18 @@ "devDependencies": { "@eslint/eslintrc": "^3", "@tailwindcss/postcss": "^4", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.2", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", + "@vitejs/plugin-react": "^6.0.2", "eslint": "^9", "eslint-config-next": "16.1.6", + "jsdom": "^29.1.1", "tailwindcss": "^4", "typescript": "^5", + "vitest": "^4.1.8", "zod": "^3.23.8" } } diff --git a/apps/app/src/components/generative-ui/export-utils.ts b/apps/app/src/components/generative-ui/export-utils.ts index 381586b..5bdee52 100644 --- a/apps/app/src/components/generative-ui/export-utils.ts +++ b/apps/app/src/components/generative-ui/export-utils.ts @@ -1,4 +1,9 @@ -import { THEME_CSS, SVG_CLASSES_CSS, FORM_STYLES_CSS } from "./widget-renderer"; +import { + THEME_CSS, + SVG_CLASSES_CSS, + FORM_STYLES_WITH_STAGGER_CSS as FORM_STYLES_CSS, + IMPORTMAP_SCRIPT_TAG, +} from "@repo/design-system"; const CHART_COLORS = [ "#3b82f6", @@ -12,20 +17,7 @@ const CHART_COLORS = [ // Import map matching widget-renderer's assembleShell — allows widgets that // use bare specifiers (e.g. `import * as THREE from "three"`) to work standalone. -const IMPORT_MAP = ``; +const IMPORT_MAP = IMPORTMAP_SCRIPT_TAG; /** * Wrap a raw HTML fragment (the same string passed to WidgetRenderer) diff --git a/apps/app/src/components/generative-ui/plan-card.test.tsx b/apps/app/src/components/generative-ui/plan-card.test.tsx new file mode 100644 index 0000000..daee2fb --- /dev/null +++ b/apps/app/src/components/generative-ui/plan-card.test.tsx @@ -0,0 +1,23 @@ +import { describe, it, expect } from "vitest"; +import { render, screen } from "@testing-library/react"; +import "@testing-library/jest-dom/vitest"; +import { PlanCard } from "@/components/generative-ui/plan-card"; + +describe("PlanCard", () => { + it("renders the completed plan with technology and key elements", () => { + render( + + ); + + expect(screen.getByText("Plan: inline SVG")).toBeInTheDocument(); + expect( + screen.getByText("Render a bar chart of monthly revenue") + ).toBeInTheDocument(); + expect(screen.getByText("12 bars")).toBeInTheDocument(); + }); +}); diff --git a/apps/app/src/components/generative-ui/widget-renderer.tsx b/apps/app/src/components/generative-ui/widget-renderer.tsx index 11e7d44..56efe26 100644 --- a/apps/app/src/components/generative-ui/widget-renderer.tsx +++ b/apps/app/src/components/generative-ui/widget-renderer.tsx @@ -2,6 +2,12 @@ import { useEffect, useRef, useState, useCallback } from "react"; import { z } from "zod"; +import { + THEME_CSS, + SVG_CLASSES_CSS, + FORM_STYLES_WITH_STAGGER_CSS, + IMPORTMAP_SCRIPT_TAG, +} from "@repo/design-system"; import { ExportOverlay } from "./export-overlay"; import { IDIOMORPH_JS } from "./idiomorph-inline"; @@ -25,312 +31,9 @@ export const WidgetRendererProps = z.object({ type WidgetRendererProps = z.infer; -// ─── Injected CSS: Theme Variables (Layer 3) ───────────────────────── -export const THEME_CSS = ` -:root { - --color-background-primary: #ffffff; - --color-background-secondary: #f7f6f3; - --color-background-tertiary: #efeee9; - --color-background-info: #E6F1FB; - --color-background-danger: #FCEBEB; - --color-background-success: #EAF3DE; - --color-background-warning: #FAEEDA; - - --color-text-primary: #1a1a1a; - --color-text-secondary: #73726c; - --color-text-tertiary: #9c9a92; - --color-text-info: #185FA5; - --color-text-danger: #A32D2D; - --color-text-success: #3B6D11; - --color-text-warning: #854F0B; - - --color-border-primary: rgba(0, 0, 0, 0.4); - --color-border-secondary: rgba(0, 0, 0, 0.3); - --color-border-tertiary: rgba(0, 0, 0, 0.15); - --color-border-info: #185FA5; - --color-border-danger: #A32D2D; - --color-border-success: #3B6D11; - --color-border-warning: #854F0B; - - --font-sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; - --font-serif: Georgia, "Times New Roman", serif; - --font-mono: "SF Mono", "Fira Code", "Fira Mono", monospace; - - --border-radius-md: 8px; - --border-radius-lg: 12px; - --border-radius-xl: 16px; - - --p: var(--color-text-primary); - --s: var(--color-text-secondary); - --t: var(--color-text-tertiary); - --bg2: var(--color-background-secondary); - --b: var(--color-border-tertiary); -} - -@media (prefers-color-scheme: dark) { - :root { - --color-background-primary: #1a1a18; - --color-background-secondary: #2c2c2a; - --color-background-tertiary: #222220; - --color-background-info: #0C447C; - --color-background-danger: #501313; - --color-background-success: #173404; - --color-background-warning: #412402; - - --color-text-primary: #e8e6de; - --color-text-secondary: #9c9a92; - --color-text-tertiary: #73726c; - --color-text-info: #85B7EB; - --color-text-danger: #F09595; - --color-text-success: #97C459; - --color-text-warning: #EF9F27; - - --color-border-primary: rgba(255, 255, 255, 0.4); - --color-border-secondary: rgba(255, 255, 255, 0.3); - --color-border-tertiary: rgba(255, 255, 255, 0.15); - --color-border-info: #85B7EB; - --color-border-danger: #F09595; - --color-border-success: #97C459; - --color-border-warning: #EF9F27; - } -} -`; - -// ─── Injected CSS: SVG Pre-Built Classes (Layer 4) ─────────────────── -export const SVG_CLASSES_CSS = ` -svg text.t { font: 400 14px var(--font-sans); fill: var(--p); } -svg text.ts { font: 400 12px var(--font-sans); fill: var(--s); } -svg text.th { font: 500 14px var(--font-sans); fill: var(--p); } - -svg .box > rect, svg .box > circle, svg .box > ellipse { fill: var(--bg2); stroke: var(--b); } -svg .node { cursor: pointer; } -svg .node:hover { opacity: 0.8; } -svg .arr { stroke: var(--s); stroke-width: 1.5; fill: none; } -svg .leader { stroke: var(--t); stroke-width: 0.5; stroke-dasharray: 4 4; fill: none; } - -/* Purple */ -svg .c-purple > rect, svg .c-purple > circle, svg .c-purple > ellipse, -svg rect.c-purple, svg circle.c-purple, svg ellipse.c-purple { fill: #EEEDFE; stroke: #534AB7; } -svg .c-purple text.th, svg .c-purple text.t { fill: #3C3489; } -svg .c-purple text.ts { fill: #534AB7; } - -/* Teal */ -svg .c-teal > rect, svg .c-teal > circle, svg .c-teal > ellipse, -svg rect.c-teal, svg circle.c-teal, svg ellipse.c-teal { fill: #E1F5EE; stroke: #0F6E56; } -svg .c-teal text.th, svg .c-teal text.t { fill: #085041; } -svg .c-teal text.ts { fill: #0F6E56; } - -/* Coral */ -svg .c-coral > rect, svg .c-coral > circle, svg .c-coral > ellipse, -svg rect.c-coral, svg circle.c-coral, svg ellipse.c-coral { fill: #FAECE7; stroke: #993C1D; } -svg .c-coral text.th, svg .c-coral text.t { fill: #712B13; } -svg .c-coral text.ts { fill: #993C1D; } - -/* Pink */ -svg .c-pink > rect, svg .c-pink > circle, svg .c-pink > ellipse, -svg rect.c-pink, svg circle.c-pink, svg ellipse.c-pink { fill: #FBEAF0; stroke: #993556; } -svg .c-pink text.th, svg .c-pink text.t { fill: #72243E; } -svg .c-pink text.ts { fill: #993556; } - -/* Gray */ -svg .c-gray > rect, svg .c-gray > circle, svg .c-gray > ellipse, -svg rect.c-gray, svg circle.c-gray, svg ellipse.c-gray { fill: #F1EFE8; stroke: #5F5E5A; } -svg .c-gray text.th, svg .c-gray text.t { fill: #444441; } -svg .c-gray text.ts { fill: #5F5E5A; } - -/* Blue */ -svg .c-blue > rect, svg .c-blue > circle, svg .c-blue > ellipse, -svg rect.c-blue, svg circle.c-blue, svg ellipse.c-blue { fill: #E6F1FB; stroke: #185FA5; } -svg .c-blue text.th, svg .c-blue text.t { fill: #0C447C; } -svg .c-blue text.ts { fill: #185FA5; } - -/* Green */ -svg .c-green > rect, svg .c-green > circle, svg .c-green > ellipse, -svg rect.c-green, svg circle.c-green, svg ellipse.c-green { fill: #EAF3DE; stroke: #3B6D11; } -svg .c-green text.th, svg .c-green text.t { fill: #27500A; } -svg .c-green text.ts { fill: #3B6D11; } - -/* Amber */ -svg .c-amber > rect, svg .c-amber > circle, svg .c-amber > ellipse, -svg rect.c-amber, svg circle.c-amber, svg ellipse.c-amber { fill: #FAEEDA; stroke: #854F0B; } -svg .c-amber text.th, svg .c-amber text.t { fill: #633806; } -svg .c-amber text.ts { fill: #854F0B; } - -/* Red */ -svg .c-red > rect, svg .c-red > circle, svg .c-red > ellipse, -svg rect.c-red, svg circle.c-red, svg ellipse.c-red { fill: #FCEBEB; stroke: #A32D2D; } -svg .c-red text.th, svg .c-red text.t { fill: #791F1F; } -svg .c-red text.ts { fill: #A32D2D; } - -/* Dark mode overrides */ -@media (prefers-color-scheme: dark) { - svg text.t { fill: #e8e6de; } - svg text.ts { fill: #9c9a92; } - svg text.th { fill: #e8e6de; } - - svg .c-purple > rect, svg .c-purple > circle, svg .c-purple > ellipse, - svg rect.c-purple, svg circle.c-purple, svg ellipse.c-purple { fill: #3C3489; stroke: #AFA9EC; } - svg .c-purple text.th, svg .c-purple text.t { fill: #CECBF6; } - svg .c-purple text.ts { fill: #AFA9EC; } - - svg .c-teal > rect, svg .c-teal > circle, svg .c-teal > ellipse, - svg rect.c-teal, svg circle.c-teal, svg ellipse.c-teal { fill: #085041; stroke: #5DCAA5; } - svg .c-teal text.th, svg .c-teal text.t { fill: #9FE1CB; } - svg .c-teal text.ts { fill: #5DCAA5; } - - svg .c-coral > rect, svg .c-coral > circle, svg .c-coral > ellipse, - svg rect.c-coral, svg circle.c-coral, svg ellipse.c-coral { fill: #712B13; stroke: #F0997B; } - svg .c-coral text.th, svg .c-coral text.t { fill: #F5C4B3; } - svg .c-coral text.ts { fill: #F0997B; } - - svg .c-pink > rect, svg .c-pink > circle, svg .c-pink > ellipse, - svg rect.c-pink, svg circle.c-pink, svg ellipse.c-pink { fill: #72243E; stroke: #ED93B1; } - svg .c-pink text.th, svg .c-pink text.t { fill: #F4C0D1; } - svg .c-pink text.ts { fill: #ED93B1; } - - svg .c-gray > rect, svg .c-gray > circle, svg .c-gray > ellipse, - svg rect.c-gray, svg circle.c-gray, svg ellipse.c-gray { fill: #444441; stroke: #B4B2A9; } - svg .c-gray text.th, svg .c-gray text.t { fill: #D3D1C7; } - svg .c-gray text.ts { fill: #B4B2A9; } - - svg .c-blue > rect, svg .c-blue > circle, svg .c-blue > ellipse, - svg rect.c-blue, svg circle.c-blue, svg ellipse.c-blue { fill: #0C447C; stroke: #85B7EB; } - svg .c-blue text.th, svg .c-blue text.t { fill: #B5D4F4; } - svg .c-blue text.ts { fill: #85B7EB; } - - svg .c-green > rect, svg .c-green > circle, svg .c-green > ellipse, - svg rect.c-green, svg circle.c-green, svg ellipse.c-green { fill: #27500A; stroke: #97C459; } - svg .c-green text.th, svg .c-green text.t { fill: #C0DD97; } - svg .c-green text.ts { fill: #97C459; } - - svg .c-amber > rect, svg .c-amber > circle, svg .c-amber > ellipse, - svg rect.c-amber, svg circle.c-amber, svg ellipse.c-amber { fill: #633806; stroke: #EF9F27; } - svg .c-amber text.th, svg .c-amber text.t { fill: #FAC775; } - svg .c-amber text.ts { fill: #EF9F27; } - - svg .c-red > rect, svg .c-red > circle, svg .c-red > ellipse, - svg rect.c-red, svg circle.c-red, svg ellipse.c-red { fill: #791F1F; stroke: #F09595; } - svg .c-red text.th, svg .c-red text.t { fill: #F7C1C1; } - svg .c-red text.ts { fill: #F09595; } -} -`; - -// ─── Injected CSS: Form Element Styles (Layer 5) ───────────────────── -export const FORM_STYLES_CSS = ` -* { box-sizing: border-box; margin: 0; } - -html { background: transparent; } - -body { - font-family: var(--font-sans); - font-size: 16px; - line-height: 1.7; - color: var(--color-text-primary); - background: transparent; - -webkit-font-smoothing: antialiased; -} - -button { - font-family: inherit; - font-size: 14px; - padding: 6px 16px; - border: 0.5px solid var(--color-border-secondary); - border-radius: var(--border-radius-md); - background: transparent; - color: var(--color-text-primary); - cursor: pointer; - transition: background 0.15s, transform 0.1s; -} -button:hover { background: var(--color-background-secondary); } -button:active { transform: scale(0.98); } - -input[type="text"], -input[type="number"], -input[type="email"], -input[type="search"], -textarea, -select { - font-family: inherit; - font-size: 14px; - padding: 6px 12px; - height: 36px; - border: 0.5px solid var(--color-border-tertiary); - border-radius: var(--border-radius-md); - background: var(--color-background-primary); - color: var(--color-text-primary); - transition: border-color 0.15s; -} -input:hover, textarea:hover, select:hover { border-color: var(--color-border-secondary); } -input:focus, textarea:focus, select:focus { - outline: none; - border-color: var(--color-border-primary); - box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.06); -} -textarea { height: auto; min-height: 80px; resize: vertical; } -input::placeholder, textarea::placeholder { color: var(--color-text-tertiary); } - -input[type="range"] { - -webkit-appearance: none; - appearance: none; - height: 4px; - background: var(--color-border-tertiary); - border-radius: 2px; - border: none; - outline: none; -} -input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - width: 18px; height: 18px; - border-radius: 50%; - background: var(--color-background-primary); - border: 0.5px solid var(--color-border-secondary); - cursor: pointer; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); -} -input[type="range"]::-moz-range-thumb { - width: 18px; height: 18px; - border-radius: 50%; - background: var(--color-background-primary); - border: 0.5px solid var(--color-border-secondary); - cursor: pointer; -} - -input[type="checkbox"], input[type="radio"] { - width: 16px; height: 16px; - accent-color: var(--color-text-info); -} - -a { color: var(--color-text-info); text-decoration: none; } -a:hover { text-decoration: underline; } - -/* First render: stagger all children */ -#content.initial-render > * { - animation: fadeSlideIn 0.4s ease-out both; -} -#content.initial-render > *:nth-child(1) { animation-delay: 0s; } -#content.initial-render > *:nth-child(2) { animation-delay: 0.06s; } -#content.initial-render > *:nth-child(3) { animation-delay: 0.12s; } -#content.initial-render > *:nth-child(4) { animation-delay: 0.18s; } -#content.initial-render > *:nth-child(5) { animation-delay: 0.24s; } -#content.initial-render > *:nth-child(n+6) { animation-delay: 0.3s; } - -/* Subsequent morphs: only new elements animate in */ -.morph-enter { - animation: fadeSlideIn 0.4s ease-out both; -} - -@keyframes fadeSlideIn { - from { opacity: 0; transform: translateY(8px); } - to { opacity: 1; transform: translateY(0); } -} - -@media (prefers-reduced-motion: reduce) { - *, *::before, *::after { - animation-duration: 0.01ms !important; - animation-iteration-count: 1 !important; - } -} -`; +// ─── Injected CSS (Layers 3–5) — single-sourced from @repo/design-system ─ +export { THEME_CSS, SVG_CLASSES_CSS }; +export const FORM_STYLES_CSS = FORM_STYLES_WITH_STAGGER_CSS; // ─── Injected JS: Bridge Functions + Auto-Resize (Layers 1 & 6) ───── const BRIDGE_JS = ` @@ -485,20 +188,7 @@ function assembleShell(initialHtml: string = ""): string { - + ${IMPORTMAP_SCRIPT_TAG} =18" diff --git a/apps/mcp/src/renderer.ts b/apps/mcp/src/renderer.ts index 8ae8238..9c79ae1 100644 --- a/apps/mcp/src/renderer.ts +++ b/apps/mcp/src/renderer.ts @@ -1,293 +1,7 @@ -// OpenGenerativeUI Design System CSS and Bridge JS -// Forked from apps/app/src/components/generative-ui/widget-renderer.tsx -// WARNING: Keep in sync with the source widget-renderer.tsx when the design system changes. +// OpenGenerativeUI document assembly for the MCP server. +// Design-system CSS is single-sourced from @repo/design-system. -const THEME_CSS = ` -:root { - --color-background-primary: #ffffff; - --color-background-secondary: #f7f6f3; - --color-background-tertiary: #efeee9; - --color-background-info: #E6F1FB; - --color-background-danger: #FCEBEB; - --color-background-success: #EAF3DE; - --color-background-warning: #FAEEDA; - - --color-text-primary: #1a1a1a; - --color-text-secondary: #73726c; - --color-text-tertiary: #9c9a92; - --color-text-info: #185FA5; - --color-text-danger: #A32D2D; - --color-text-success: #3B6D11; - --color-text-warning: #854F0B; - - --color-border-primary: rgba(0, 0, 0, 0.4); - --color-border-secondary: rgba(0, 0, 0, 0.3); - --color-border-tertiary: rgba(0, 0, 0, 0.15); - --color-border-info: #185FA5; - --color-border-danger: #A32D2D; - --color-border-success: #3B6D11; - --color-border-warning: #854F0B; - - --font-sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; - --font-serif: Georgia, "Times New Roman", serif; - --font-mono: "SF Mono", "Fira Code", "Fira Mono", monospace; - - --border-radius-md: 8px; - --border-radius-lg: 12px; - --border-radius-xl: 16px; - - --p: var(--color-text-primary); - --s: var(--color-text-secondary); - --t: var(--color-text-tertiary); - --bg2: var(--color-background-secondary); - --b: var(--color-border-tertiary); -} - -@media (prefers-color-scheme: dark) { - :root { - --color-background-primary: #1a1a18; - --color-background-secondary: #2c2c2a; - --color-background-tertiary: #222220; - --color-background-info: #0C447C; - --color-background-danger: #501313; - --color-background-success: #173404; - --color-background-warning: #412402; - - --color-text-primary: #e8e6de; - --color-text-secondary: #9c9a92; - --color-text-tertiary: #73726c; - --color-text-info: #85B7EB; - --color-text-danger: #F09595; - --color-text-success: #97C459; - --color-text-warning: #EF9F27; - - --color-border-primary: rgba(255, 255, 255, 0.4); - --color-border-secondary: rgba(255, 255, 255, 0.3); - --color-border-tertiary: rgba(255, 255, 255, 0.15); - --color-border-info: #85B7EB; - --color-border-danger: #F09595; - --color-border-success: #97C459; - --color-border-warning: #EF9F27; - } -} -`; - -const SVG_CLASSES_CSS = ` -svg text.t { font: 400 14px var(--font-sans); fill: var(--p); } -svg text.ts { font: 400 12px var(--font-sans); fill: var(--s); } -svg text.th { font: 500 14px var(--font-sans); fill: var(--p); } - -svg .box > rect, svg .box > circle, svg .box > ellipse { fill: var(--bg2); stroke: var(--b); } -svg .node { cursor: pointer; } -svg .node:hover { opacity: 0.8; } -svg .arr { stroke: var(--s); stroke-width: 1.5; fill: none; } -svg .leader { stroke: var(--t); stroke-width: 0.5; stroke-dasharray: 4 4; fill: none; } - -/* Purple */ -svg .c-purple > rect, svg .c-purple > circle, svg .c-purple > ellipse, -svg rect.c-purple, svg circle.c-purple, svg ellipse.c-purple { fill: #EEEDFE; stroke: #534AB7; } -svg .c-purple text.th, svg .c-purple text.t { fill: #3C3489; } -svg .c-purple text.ts { fill: #534AB7; } - -/* Teal */ -svg .c-teal > rect, svg .c-teal > circle, svg .c-teal > ellipse, -svg rect.c-teal, svg circle.c-teal, svg ellipse.c-teal { fill: #E1F5EE; stroke: #0F6E56; } -svg .c-teal text.th, svg .c-teal text.t { fill: #085041; } -svg .c-teal text.ts { fill: #0F6E56; } - -/* Coral */ -svg .c-coral > rect, svg .c-coral > circle, svg .c-coral > ellipse, -svg rect.c-coral, svg circle.c-coral, svg ellipse.c-coral { fill: #FAECE7; stroke: #993C1D; } -svg .c-coral text.th, svg .c-coral text.t { fill: #712B13; } -svg .c-coral text.ts { fill: #993C1D; } - -/* Pink */ -svg .c-pink > rect, svg .c-pink > circle, svg .c-pink > ellipse, -svg rect.c-pink, svg circle.c-pink, svg ellipse.c-pink { fill: #FBEAF0; stroke: #993556; } -svg .c-pink text.th, svg .c-pink text.t { fill: #72243E; } -svg .c-pink text.ts { fill: #993556; } - -/* Gray */ -svg .c-gray > rect, svg .c-gray > circle, svg .c-gray > ellipse, -svg rect.c-gray, svg circle.c-gray, svg ellipse.c-gray { fill: #F1EFE8; stroke: #5F5E5A; } -svg .c-gray text.th, svg .c-gray text.t { fill: #444441; } -svg .c-gray text.ts { fill: #5F5E5A; } - -/* Blue */ -svg .c-blue > rect, svg .c-blue > circle, svg .c-blue > ellipse, -svg rect.c-blue, svg circle.c-blue, svg ellipse.c-blue { fill: #E6F1FB; stroke: #185FA5; } -svg .c-blue text.th, svg .c-blue text.t { fill: #0C447C; } -svg .c-blue text.ts { fill: #185FA5; } - -/* Green */ -svg .c-green > rect, svg .c-green > circle, svg .c-green > ellipse, -svg rect.c-green, svg circle.c-green, svg ellipse.c-green { fill: #EAF3DE; stroke: #3B6D11; } -svg .c-green text.th, svg .c-green text.t { fill: #27500A; } -svg .c-green text.ts { fill: #3B6D11; } - -/* Amber */ -svg .c-amber > rect, svg .c-amber > circle, svg .c-amber > ellipse, -svg rect.c-amber, svg circle.c-amber, svg ellipse.c-amber { fill: #FAEEDA; stroke: #854F0B; } -svg .c-amber text.th, svg .c-amber text.t { fill: #633806; } -svg .c-amber text.ts { fill: #854F0B; } - -/* Red */ -svg .c-red > rect, svg .c-red > circle, svg .c-red > ellipse, -svg rect.c-red, svg circle.c-red, svg ellipse.c-red { fill: #FCEBEB; stroke: #A32D2D; } -svg .c-red text.th, svg .c-red text.t { fill: #791F1F; } -svg .c-red text.ts { fill: #A32D2D; } - -@media (prefers-color-scheme: dark) { - svg text.t { fill: #e8e6de; } - svg text.ts { fill: #9c9a92; } - svg text.th { fill: #e8e6de; } - - svg .c-purple > rect, svg .c-purple > circle, svg .c-purple > ellipse, - svg rect.c-purple, svg circle.c-purple, svg ellipse.c-purple { fill: #3C3489; stroke: #AFA9EC; } - svg .c-purple text.th, svg .c-purple text.t { fill: #CECBF6; } - svg .c-purple text.ts { fill: #AFA9EC; } - - svg .c-teal > rect, svg .c-teal > circle, svg .c-teal > ellipse, - svg rect.c-teal, svg circle.c-teal, svg ellipse.c-teal { fill: #085041; stroke: #5DCAA5; } - svg .c-teal text.th, svg .c-teal text.t { fill: #9FE1CB; } - svg .c-teal text.ts { fill: #5DCAA5; } - - svg .c-coral > rect, svg .c-coral > circle, svg .c-coral > ellipse, - svg rect.c-coral, svg circle.c-coral, svg ellipse.c-coral { fill: #712B13; stroke: #F0997B; } - svg .c-coral text.th, svg .c-coral text.t { fill: #F5C4B3; } - svg .c-coral text.ts { fill: #F0997B; } - - svg .c-pink > rect, svg .c-pink > circle, svg .c-pink > ellipse, - svg rect.c-pink, svg circle.c-pink, svg ellipse.c-pink { fill: #72243E; stroke: #ED93B1; } - svg .c-pink text.th, svg .c-pink text.t { fill: #F4C0D1; } - svg .c-pink text.ts { fill: #ED93B1; } - - svg .c-gray > rect, svg .c-gray > circle, svg .c-gray > ellipse, - svg rect.c-gray, svg circle.c-gray, svg ellipse.c-gray { fill: #444441; stroke: #B4B2A9; } - svg .c-gray text.th, svg .c-gray text.t { fill: #D3D1C7; } - svg .c-gray text.ts { fill: #B4B2A9; } - - svg .c-blue > rect, svg .c-blue > circle, svg .c-blue > ellipse, - svg rect.c-blue, svg circle.c-blue, svg ellipse.c-blue { fill: #0C447C; stroke: #85B7EB; } - svg .c-blue text.th, svg .c-blue text.t { fill: #B5D4F4; } - svg .c-blue text.ts { fill: #85B7EB; } - - svg .c-green > rect, svg .c-green > circle, svg .c-green > ellipse, - svg rect.c-green, svg circle.c-green, svg ellipse.c-green { fill: #27500A; stroke: #97C459; } - svg .c-green text.th, svg .c-green text.t { fill: #C0DD97; } - svg .c-green text.ts { fill: #97C459; } - - svg .c-amber > rect, svg .c-amber > circle, svg .c-amber > ellipse, - svg rect.c-amber, svg circle.c-amber, svg ellipse.c-amber { fill: #633806; stroke: #EF9F27; } - svg .c-amber text.th, svg .c-amber text.t { fill: #FAC775; } - svg .c-amber text.ts { fill: #EF9F27; } - - svg .c-red > rect, svg .c-red > circle, svg .c-red > ellipse, - svg rect.c-red, svg circle.c-red, svg ellipse.c-red { fill: #791F1F; stroke: #F09595; } - svg .c-red text.th, svg .c-red text.t { fill: #F7C1C1; } - svg .c-red text.ts { fill: #F09595; } -} -`; - -const FORM_STYLES_CSS = ` -* { box-sizing: border-box; margin: 0; } -html { background: transparent; } -body { - font-family: var(--font-sans); - font-size: 16px; - line-height: 1.7; - color: var(--color-text-primary); - background: transparent; - -webkit-font-smoothing: antialiased; -} -button { - font-family: inherit; - font-size: 14px; - padding: 6px 16px; - border: 0.5px solid var(--color-border-secondary); - border-radius: var(--border-radius-md); - background: transparent; - color: var(--color-text-primary); - cursor: pointer; - transition: background 0.15s, transform 0.1s; -} -button:hover { background: var(--color-background-secondary); } -button:active { transform: scale(0.98); } -input[type="text"], -input[type="number"], -input[type="email"], -input[type="search"], -textarea, -select { - font-family: inherit; - font-size: 14px; - padding: 6px 12px; - height: 36px; - border: 0.5px solid var(--color-border-tertiary); - border-radius: var(--border-radius-md); - background: var(--color-background-primary); - color: var(--color-text-primary); - transition: border-color 0.15s; -} -input:hover, textarea:hover, select:hover { border-color: var(--color-border-secondary); } -input:focus, textarea:focus, select:focus { - outline: none; - border-color: var(--color-border-primary); - box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.06); -} -textarea { height: auto; min-height: 80px; resize: vertical; } -input::placeholder, textarea::placeholder { color: var(--color-text-tertiary); } -input[type="range"] { - -webkit-appearance: none; - appearance: none; - height: 4px; - background: var(--color-border-tertiary); - border-radius: 2px; - border: none; - outline: none; -} -input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - width: 18px; height: 18px; - border-radius: 50%; - background: var(--color-background-primary); - border: 0.5px solid var(--color-border-secondary); - cursor: pointer; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); -} -input[type="range"]::-moz-range-thumb { - width: 18px; height: 18px; - border-radius: 50%; - background: var(--color-background-primary); - border: 0.5px solid var(--color-border-secondary); - cursor: pointer; -} -input[type="checkbox"], input[type="radio"] { - width: 16px; height: 16px; - accent-color: var(--color-text-info); -} -a { color: var(--color-text-info); text-decoration: none; } -a:hover { text-decoration: underline; } -#content > * { - animation: fadeSlideIn 0.4s ease-out both; -} -#content > *:nth-child(1) { animation-delay: 0s; } -#content > *:nth-child(2) { animation-delay: 0.06s; } -#content > *:nth-child(3) { animation-delay: 0.12s; } -#content > *:nth-child(4) { animation-delay: 0.18s; } -#content > *:nth-child(5) { animation-delay: 0.24s; } -#content > *:nth-child(n+6) { animation-delay: 0.3s; } -@keyframes fadeSlideIn { - from { opacity: 0; transform: translateY(8px); } - to { opacity: 1; transform: translateY(0); } -} -@media (prefers-reduced-motion: reduce) { - *, *::before, *::after { - animation-duration: 0.01ms !important; - animation-iteration-count: 1 !important; - } -} -`; +import { THEME_CSS, SVG_CLASSES_CSS, FORM_STYLES_CSS } from "@repo/design-system"; const BRIDGE_JS = ` window.sendPrompt = function(text) { diff --git a/apps/mcp/tests/skills.test.ts b/apps/mcp/tests/skills.test.ts new file mode 100644 index 0000000..57a35e1 --- /dev/null +++ b/apps/mcp/tests/skills.test.ts @@ -0,0 +1,10 @@ +import { describe, it, expect } from "vitest"; +import { listSkills } from "../src/skills"; + +describe("listSkills", () => { + it("returns an array containing the bundled skills", () => { + const skills = listSkills(); + expect(Array.isArray(skills)).toBe(true); + expect(skills).toContain("master-agent-playbook"); + }); +}); diff --git a/apps/mcp/vitest.config.ts b/apps/mcp/vitest.config.ts new file mode 100644 index 0000000..f624398 --- /dev/null +++ b/apps/mcp/vitest.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + environment: "node", + }, +}); diff --git a/package.json b/package.json index 7369638..47442a6 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "dev:mcp": "turbo run dev --filter='open-generative-ui-mcp'", "build": "turbo run build", "lint": "turbo run lint", + "test": "turbo run test", "clean": "turbo run clean" }, "devDependencies": { diff --git a/packages/design-system/.gitignore b/packages/design-system/.gitignore new file mode 100644 index 0000000..d69234e --- /dev/null +++ b/packages/design-system/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +dist/ +.turbo/ diff --git a/packages/design-system/package.json b/packages/design-system/package.json new file mode 100644 index 0000000..e4a03c9 --- /dev/null +++ b/packages/design-system/package.json @@ -0,0 +1,26 @@ +{ + "name": "@repo/design-system", + "version": "0.1.0", + "description": "Shared OpenGenerativeUI design-system CSS and import map", + "private": true, + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, + "scripts": { + "build": "tsc", + "lint": "tsc --noEmit", + "test": "vitest run", + "clean": "rm -rf dist" + }, + "devDependencies": { + "@types/node": "^20", + "typescript": "^5", + "vitest": "^4.1.8" + } +} diff --git a/packages/design-system/src/__tests__/design-system.test.ts b/packages/design-system/src/__tests__/design-system.test.ts new file mode 100644 index 0000000..12cd648 --- /dev/null +++ b/packages/design-system/src/__tests__/design-system.test.ts @@ -0,0 +1,70 @@ +import { describe, it, expect } from "vitest"; +import { + THEME_CSS, + SVG_CLASSES_CSS, + FORM_STYLES_CSS, + INITIAL_RENDER_STAGGER_CSS, + FORM_STYLES_WITH_STAGGER_CSS, + IMPORTMAP, + IMPORTMAP_SCRIPT_TAG, +} from "../index.js"; + +// Built via join so the single-source guard test only matches real CSS definitions. +const TOKEN_DEFINITION = ["--color-background-primary", ":"].join(""); + +describe("THEME_CSS", () => { + it("defines the design-system color tokens", () => { + expect(THEME_CSS).toContain(TOKEN_DEFINITION); + }); + + it("includes dark-mode overrides", () => { + expect(THEME_CSS).toContain("@media (prefers-color-scheme: dark)"); + }); +}); + +describe("SVG_CLASSES_CSS", () => { + it("includes the pre-built SVG color classes", () => { + expect(SVG_CLASSES_CSS).toContain(".c-purple"); + }); +}); + +describe("FORM_STYLES_CSS", () => { + it("styles form elements", () => { + expect(FORM_STYLES_CSS).toContain('input[type="text"],'); + expect(FORM_STYLES_CSS).toContain("button {"); + }); + + it("does not include the initial-render stagger block", () => { + expect(FORM_STYLES_CSS).not.toContain(".initial-render"); + }); +}); + +describe("INITIAL_RENDER_STAGGER_CSS", () => { + it("contains the initial-render stagger rules", () => { + expect(INITIAL_RENDER_STAGGER_CSS).toContain(".initial-render"); + }); +}); + +describe("FORM_STYLES_WITH_STAGGER_CSS", () => { + it("contains the initial-render stagger rules", () => { + expect(FORM_STYLES_WITH_STAGGER_CSS).toContain(".initial-render"); + expect(FORM_STYLES_WITH_STAGGER_CSS).toContain(INITIAL_RENDER_STAGGER_CSS); + }); +}); + +describe("IMPORTMAP", () => { + it("maps three/gsap/d3/chart.js to esm.sh", () => { + for (const pkg of ["three", "gsap", "d3", "chart.js"]) { + expect(IMPORTMAP.imports[pkg]).toBe(`https://esm.sh/${pkg}`); + expect(IMPORTMAP.imports[`${pkg}/`]).toBe(`https://esm.sh/${pkg}/`); + } + }); +}); + +describe("IMPORTMAP_SCRIPT_TAG", () => { + it("is a script tag containing the import map", () => { + expect(IMPORTMAP_SCRIPT_TAG.startsWith('")).toBe(true); + expect(IMPORTMAP_SCRIPT_TAG).toContain('"three": "https://esm.sh/three"'); + }); +}); diff --git a/packages/design-system/src/__tests__/single-source.test.ts b/packages/design-system/src/__tests__/single-source.test.ts new file mode 100644 index 0000000..447b5e3 --- /dev/null +++ b/packages/design-system/src/__tests__/single-source.test.ts @@ -0,0 +1,35 @@ +import { describe, it, expect } from "vitest"; +import { readdirSync, readFileSync } from "node:fs"; +import { dirname, join, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +// Built via join so this test file itself never matches the needle. +const TOKEN_DEFINITION = ["--color-background-primary", ":"].join(""); + +const REPO_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "../../../.."); +const SCAN_ROOTS = [join(REPO_ROOT, "apps"), join(REPO_ROOT, "packages")]; +const SKIP_DIRS = new Set(["node_modules", "dist", ".next"]); +const EXTENSIONS = [".ts", ".tsx"]; + +function collectSourceFiles(dir: string, out: string[] = []): string[] { + for (const entry of readdirSync(dir, { withFileTypes: true })) { + const path = join(dir, entry.name); + if (entry.isDirectory()) { + if (!SKIP_DIRS.has(entry.name)) collectSourceFiles(path, out); + } else if (EXTENSIONS.some((ext) => entry.name.endsWith(ext))) { + out.push(path); + } + } + return out; +} + +describe("design-system single source", () => { + it("defines the theme tokens in exactly one source file", () => { + const matches = SCAN_ROOTS.flatMap((root) => collectSourceFiles(root)).filter( + (file) => readFileSync(file, "utf8").includes(TOKEN_DEFINITION) + ); + expect(matches).toEqual([ + join(REPO_ROOT, "packages/design-system/src/index.ts"), + ]); + }); +}); diff --git a/packages/design-system/src/index.ts b/packages/design-system/src/index.ts new file mode 100644 index 0000000..d0afd2d --- /dev/null +++ b/packages/design-system/src/index.ts @@ -0,0 +1,451 @@ +// OpenGenerativeUI design system: theme tokens, SVG classes, form styles, +// and the CDN import map shared by the Next.js app and the MCP server. + +// ─── Theme Variables ───────────────────────────────────────────────── +export const THEME_CSS = ` +:root { + --color-background-primary: #ffffff; + --color-background-secondary: #f7f6f3; + --color-background-tertiary: #efeee9; + --color-background-info: #E6F1FB; + --color-background-danger: #FCEBEB; + --color-background-success: #EAF3DE; + --color-background-warning: #FAEEDA; + + --color-text-primary: #1a1a1a; + --color-text-secondary: #73726c; + --color-text-tertiary: #9c9a92; + --color-text-info: #185FA5; + --color-text-danger: #A32D2D; + --color-text-success: #3B6D11; + --color-text-warning: #854F0B; + + --color-border-primary: rgba(0, 0, 0, 0.4); + --color-border-secondary: rgba(0, 0, 0, 0.3); + --color-border-tertiary: rgba(0, 0, 0, 0.15); + --color-border-info: #185FA5; + --color-border-danger: #A32D2D; + --color-border-success: #3B6D11; + --color-border-warning: #854F0B; + + --font-sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; + --font-serif: Georgia, "Times New Roman", serif; + --font-mono: "SF Mono", "Fira Code", "Fira Mono", monospace; + + --border-radius-md: 8px; + --border-radius-lg: 12px; + --border-radius-xl: 16px; + + --p: var(--color-text-primary); + --s: var(--color-text-secondary); + --t: var(--color-text-tertiary); + --bg2: var(--color-background-secondary); + --b: var(--color-border-tertiary); +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background-primary: #1a1a18; + --color-background-secondary: #2c2c2a; + --color-background-tertiary: #222220; + --color-background-info: #0C447C; + --color-background-danger: #501313; + --color-background-success: #173404; + --color-background-warning: #412402; + + --color-text-primary: #e8e6de; + --color-text-secondary: #9c9a92; + --color-text-tertiary: #73726c; + --color-text-info: #85B7EB; + --color-text-danger: #F09595; + --color-text-success: #97C459; + --color-text-warning: #EF9F27; + + --color-border-primary: rgba(255, 255, 255, 0.4); + --color-border-secondary: rgba(255, 255, 255, 0.3); + --color-border-tertiary: rgba(255, 255, 255, 0.15); + --color-border-info: #85B7EB; + --color-border-danger: #F09595; + --color-border-success: #97C459; + --color-border-warning: #EF9F27; + } +} +`; + +// ─── SVG Pre-Built Classes ─────────────────────────────────────────── +export const SVG_CLASSES_CSS = ` +svg text.t { font: 400 14px var(--font-sans); fill: var(--p); } +svg text.ts { font: 400 12px var(--font-sans); fill: var(--s); } +svg text.th { font: 500 14px var(--font-sans); fill: var(--p); } + +svg .box > rect, svg .box > circle, svg .box > ellipse { fill: var(--bg2); stroke: var(--b); } +svg .node { cursor: pointer; } +svg .node:hover { opacity: 0.8; } +svg .arr { stroke: var(--s); stroke-width: 1.5; fill: none; } +svg .leader { stroke: var(--t); stroke-width: 0.5; stroke-dasharray: 4 4; fill: none; } + +/* Purple */ +svg .c-purple > rect, svg .c-purple > circle, svg .c-purple > ellipse, +svg rect.c-purple, svg circle.c-purple, svg ellipse.c-purple { fill: #EEEDFE; stroke: #534AB7; } +svg .c-purple text.th, svg .c-purple text.t { fill: #3C3489; } +svg .c-purple text.ts { fill: #534AB7; } + +/* Teal */ +svg .c-teal > rect, svg .c-teal > circle, svg .c-teal > ellipse, +svg rect.c-teal, svg circle.c-teal, svg ellipse.c-teal { fill: #E1F5EE; stroke: #0F6E56; } +svg .c-teal text.th, svg .c-teal text.t { fill: #085041; } +svg .c-teal text.ts { fill: #0F6E56; } + +/* Coral */ +svg .c-coral > rect, svg .c-coral > circle, svg .c-coral > ellipse, +svg rect.c-coral, svg circle.c-coral, svg ellipse.c-coral { fill: #FAECE7; stroke: #993C1D; } +svg .c-coral text.th, svg .c-coral text.t { fill: #712B13; } +svg .c-coral text.ts { fill: #993C1D; } + +/* Pink */ +svg .c-pink > rect, svg .c-pink > circle, svg .c-pink > ellipse, +svg rect.c-pink, svg circle.c-pink, svg ellipse.c-pink { fill: #FBEAF0; stroke: #993556; } +svg .c-pink text.th, svg .c-pink text.t { fill: #72243E; } +svg .c-pink text.ts { fill: #993556; } + +/* Gray */ +svg .c-gray > rect, svg .c-gray > circle, svg .c-gray > ellipse, +svg rect.c-gray, svg circle.c-gray, svg ellipse.c-gray { fill: #F1EFE8; stroke: #5F5E5A; } +svg .c-gray text.th, svg .c-gray text.t { fill: #444441; } +svg .c-gray text.ts { fill: #5F5E5A; } + +/* Blue */ +svg .c-blue > rect, svg .c-blue > circle, svg .c-blue > ellipse, +svg rect.c-blue, svg circle.c-blue, svg ellipse.c-blue { fill: #E6F1FB; stroke: #185FA5; } +svg .c-blue text.th, svg .c-blue text.t { fill: #0C447C; } +svg .c-blue text.ts { fill: #185FA5; } + +/* Green */ +svg .c-green > rect, svg .c-green > circle, svg .c-green > ellipse, +svg rect.c-green, svg circle.c-green, svg ellipse.c-green { fill: #EAF3DE; stroke: #3B6D11; } +svg .c-green text.th, svg .c-green text.t { fill: #27500A; } +svg .c-green text.ts { fill: #3B6D11; } + +/* Amber */ +svg .c-amber > rect, svg .c-amber > circle, svg .c-amber > ellipse, +svg rect.c-amber, svg circle.c-amber, svg ellipse.c-amber { fill: #FAEEDA; stroke: #854F0B; } +svg .c-amber text.th, svg .c-amber text.t { fill: #633806; } +svg .c-amber text.ts { fill: #854F0B; } + +/* Red */ +svg .c-red > rect, svg .c-red > circle, svg .c-red > ellipse, +svg rect.c-red, svg circle.c-red, svg ellipse.c-red { fill: #FCEBEB; stroke: #A32D2D; } +svg .c-red text.th, svg .c-red text.t { fill: #791F1F; } +svg .c-red text.ts { fill: #A32D2D; } + +/* Dark mode overrides */ +@media (prefers-color-scheme: dark) { + svg text.t { fill: #e8e6de; } + svg text.ts { fill: #9c9a92; } + svg text.th { fill: #e8e6de; } + + svg .c-purple > rect, svg .c-purple > circle, svg .c-purple > ellipse, + svg rect.c-purple, svg circle.c-purple, svg ellipse.c-purple { fill: #3C3489; stroke: #AFA9EC; } + svg .c-purple text.th, svg .c-purple text.t { fill: #CECBF6; } + svg .c-purple text.ts { fill: #AFA9EC; } + + svg .c-teal > rect, svg .c-teal > circle, svg .c-teal > ellipse, + svg rect.c-teal, svg circle.c-teal, svg ellipse.c-teal { fill: #085041; stroke: #5DCAA5; } + svg .c-teal text.th, svg .c-teal text.t { fill: #9FE1CB; } + svg .c-teal text.ts { fill: #5DCAA5; } + + svg .c-coral > rect, svg .c-coral > circle, svg .c-coral > ellipse, + svg rect.c-coral, svg circle.c-coral, svg ellipse.c-coral { fill: #712B13; stroke: #F0997B; } + svg .c-coral text.th, svg .c-coral text.t { fill: #F5C4B3; } + svg .c-coral text.ts { fill: #F0997B; } + + svg .c-pink > rect, svg .c-pink > circle, svg .c-pink > ellipse, + svg rect.c-pink, svg circle.c-pink, svg ellipse.c-pink { fill: #72243E; stroke: #ED93B1; } + svg .c-pink text.th, svg .c-pink text.t { fill: #F4C0D1; } + svg .c-pink text.ts { fill: #ED93B1; } + + svg .c-gray > rect, svg .c-gray > circle, svg .c-gray > ellipse, + svg rect.c-gray, svg circle.c-gray, svg ellipse.c-gray { fill: #444441; stroke: #B4B2A9; } + svg .c-gray text.th, svg .c-gray text.t { fill: #D3D1C7; } + svg .c-gray text.ts { fill: #B4B2A9; } + + svg .c-blue > rect, svg .c-blue > circle, svg .c-blue > ellipse, + svg rect.c-blue, svg circle.c-blue, svg ellipse.c-blue { fill: #0C447C; stroke: #85B7EB; } + svg .c-blue text.th, svg .c-blue text.t { fill: #B5D4F4; } + svg .c-blue text.ts { fill: #85B7EB; } + + svg .c-green > rect, svg .c-green > circle, svg .c-green > ellipse, + svg rect.c-green, svg circle.c-green, svg ellipse.c-green { fill: #27500A; stroke: #97C459; } + svg .c-green text.th, svg .c-green text.t { fill: #C0DD97; } + svg .c-green text.ts { fill: #97C459; } + + svg .c-amber > rect, svg .c-amber > circle, svg .c-amber > ellipse, + svg rect.c-amber, svg circle.c-amber, svg ellipse.c-amber { fill: #633806; stroke: #EF9F27; } + svg .c-amber text.th, svg .c-amber text.t { fill: #FAC775; } + svg .c-amber text.ts { fill: #EF9F27; } + + svg .c-red > rect, svg .c-red > circle, svg .c-red > ellipse, + svg rect.c-red, svg circle.c-red, svg ellipse.c-red { fill: #791F1F; stroke: #F09595; } + svg .c-red text.th, svg .c-red text.t { fill: #F7C1C1; } + svg .c-red text.ts { fill: #F09595; } +} +`; + +// ─── Form Element Styles (base, no entrance stagger) ───────────────── +// Used by the MCP server's static documents, which animate via #content > *. +export const FORM_STYLES_CSS = ` +* { box-sizing: border-box; margin: 0; } +html { background: transparent; } +body { + font-family: var(--font-sans); + font-size: 16px; + line-height: 1.7; + color: var(--color-text-primary); + background: transparent; + -webkit-font-smoothing: antialiased; +} +button { + font-family: inherit; + font-size: 14px; + padding: 6px 16px; + border: 0.5px solid var(--color-border-secondary); + border-radius: var(--border-radius-md); + background: transparent; + color: var(--color-text-primary); + cursor: pointer; + transition: background 0.15s, transform 0.1s; +} +button:hover { background: var(--color-background-secondary); } +button:active { transform: scale(0.98); } +input[type="text"], +input[type="number"], +input[type="email"], +input[type="search"], +textarea, +select { + font-family: inherit; + font-size: 14px; + padding: 6px 12px; + height: 36px; + border: 0.5px solid var(--color-border-tertiary); + border-radius: var(--border-radius-md); + background: var(--color-background-primary); + color: var(--color-text-primary); + transition: border-color 0.15s; +} +input:hover, textarea:hover, select:hover { border-color: var(--color-border-secondary); } +input:focus, textarea:focus, select:focus { + outline: none; + border-color: var(--color-border-primary); + box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.06); +} +textarea { height: auto; min-height: 80px; resize: vertical; } +input::placeholder, textarea::placeholder { color: var(--color-text-tertiary); } +input[type="range"] { + -webkit-appearance: none; + appearance: none; + height: 4px; + background: var(--color-border-tertiary); + border-radius: 2px; + border: none; + outline: none; +} +input[type="range"]::-webkit-slider-thumb { + -webkit-appearance: none; + width: 18px; height: 18px; + border-radius: 50%; + background: var(--color-background-primary); + border: 0.5px solid var(--color-border-secondary); + cursor: pointer; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); +} +input[type="range"]::-moz-range-thumb { + width: 18px; height: 18px; + border-radius: 50%; + background: var(--color-background-primary); + border: 0.5px solid var(--color-border-secondary); + cursor: pointer; +} +input[type="checkbox"], input[type="radio"] { + width: 16px; height: 16px; + accent-color: var(--color-text-info); +} +a { color: var(--color-text-info); text-decoration: none; } +a:hover { text-decoration: underline; } +#content > * { + animation: fadeSlideIn 0.4s ease-out both; +} +#content > *:nth-child(1) { animation-delay: 0s; } +#content > *:nth-child(2) { animation-delay: 0.06s; } +#content > *:nth-child(3) { animation-delay: 0.12s; } +#content > *:nth-child(4) { animation-delay: 0.18s; } +#content > *:nth-child(5) { animation-delay: 0.24s; } +#content > *:nth-child(n+6) { animation-delay: 0.3s; } +@keyframes fadeSlideIn { + from { opacity: 0; transform: translateY(8px); } + to { opacity: 1; transform: translateY(0); } +} +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + } +} +`; + +// ─── Initial-Render Stagger (app-only addition) ────────────────────── +// The streaming widget renderer gates the entrance animation behind the +// .initial-render class and animates morphed-in nodes via .morph-enter. +export const INITIAL_RENDER_STAGGER_CSS = `/* First render: stagger all children */ +#content.initial-render > * { + animation: fadeSlideIn 0.4s ease-out both; +} +#content.initial-render > *:nth-child(1) { animation-delay: 0s; } +#content.initial-render > *:nth-child(2) { animation-delay: 0.06s; } +#content.initial-render > *:nth-child(3) { animation-delay: 0.12s; } +#content.initial-render > *:nth-child(4) { animation-delay: 0.18s; } +#content.initial-render > *:nth-child(5) { animation-delay: 0.24s; } +#content.initial-render > *:nth-child(n+6) { animation-delay: 0.3s; } + +/* Subsequent morphs: only new elements animate in */ +.morph-enter { + animation: fadeSlideIn 0.4s ease-out both; +}`; + +// ─── Form Element Styles + Initial-Render Stagger ──────────────────── +export const FORM_STYLES_WITH_STAGGER_CSS = ` +* { box-sizing: border-box; margin: 0; } + +html { background: transparent; } + +body { + font-family: var(--font-sans); + font-size: 16px; + line-height: 1.7; + color: var(--color-text-primary); + background: transparent; + -webkit-font-smoothing: antialiased; +} + +button { + font-family: inherit; + font-size: 14px; + padding: 6px 16px; + border: 0.5px solid var(--color-border-secondary); + border-radius: var(--border-radius-md); + background: transparent; + color: var(--color-text-primary); + cursor: pointer; + transition: background 0.15s, transform 0.1s; +} +button:hover { background: var(--color-background-secondary); } +button:active { transform: scale(0.98); } + +input[type="text"], +input[type="number"], +input[type="email"], +input[type="search"], +textarea, +select { + font-family: inherit; + font-size: 14px; + padding: 6px 12px; + height: 36px; + border: 0.5px solid var(--color-border-tertiary); + border-radius: var(--border-radius-md); + background: var(--color-background-primary); + color: var(--color-text-primary); + transition: border-color 0.15s; +} +input:hover, textarea:hover, select:hover { border-color: var(--color-border-secondary); } +input:focus, textarea:focus, select:focus { + outline: none; + border-color: var(--color-border-primary); + box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.06); +} +textarea { height: auto; min-height: 80px; resize: vertical; } +input::placeholder, textarea::placeholder { color: var(--color-text-tertiary); } + +input[type="range"] { + -webkit-appearance: none; + appearance: none; + height: 4px; + background: var(--color-border-tertiary); + border-radius: 2px; + border: none; + outline: none; +} +input[type="range"]::-webkit-slider-thumb { + -webkit-appearance: none; + width: 18px; height: 18px; + border-radius: 50%; + background: var(--color-background-primary); + border: 0.5px solid var(--color-border-secondary); + cursor: pointer; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); +} +input[type="range"]::-moz-range-thumb { + width: 18px; height: 18px; + border-radius: 50%; + background: var(--color-background-primary); + border: 0.5px solid var(--color-border-secondary); + cursor: pointer; +} + +input[type="checkbox"], input[type="radio"] { + width: 16px; height: 16px; + accent-color: var(--color-text-info); +} + +a { color: var(--color-text-info); text-decoration: none; } +a:hover { text-decoration: underline; } + +/* First render: stagger all children */ +#content.initial-render > * { + animation: fadeSlideIn 0.4s ease-out both; +} +#content.initial-render > *:nth-child(1) { animation-delay: 0s; } +#content.initial-render > *:nth-child(2) { animation-delay: 0.06s; } +#content.initial-render > *:nth-child(3) { animation-delay: 0.12s; } +#content.initial-render > *:nth-child(4) { animation-delay: 0.18s; } +#content.initial-render > *:nth-child(5) { animation-delay: 0.24s; } +#content.initial-render > *:nth-child(n+6) { animation-delay: 0.3s; } + +/* Subsequent morphs: only new elements animate in */ +.morph-enter { + animation: fadeSlideIn 0.4s ease-out both; +} + +@keyframes fadeSlideIn { + from { opacity: 0; transform: translateY(8px); } + to { opacity: 1; transform: translateY(0); } +} + +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + } +} +`; + +// ─── CDN Import Map ────────────────────────────────────────────────── +export const IMPORTMAP = { + imports: { + "three": "https://esm.sh/three", + "three/": "https://esm.sh/three/", + "gsap": "https://esm.sh/gsap", + "gsap/": "https://esm.sh/gsap/", + "d3": "https://esm.sh/d3", + "d3/": "https://esm.sh/d3/", + "chart.js": "https://esm.sh/chart.js", + "chart.js/": "https://esm.sh/chart.js/", + }, +} as const satisfies { imports: Record }; + +export const IMPORTMAP_SCRIPT_TAG = ``; diff --git a/packages/design-system/tsconfig.json b/packages/design-system/tsconfig.json new file mode 100644 index 0000000..586c3ce --- /dev/null +++ b/packages/design-system/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "outDir": "dist", + "declaration": true, + "strict": true, + "skipLibCheck": true, + "esModuleInterop": true + }, + "include": ["src/**/*.ts"], + "exclude": ["src/__tests__"] +} diff --git a/packages/design-system/vitest.config.ts b/packages/design-system/vitest.config.ts new file mode 100644 index 0000000..f624398 --- /dev/null +++ b/packages/design-system/vitest.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + environment: "node", + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 20c128f..022a309 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,22 +22,25 @@ importers: dependencies: '@ag-ui/a2ui-middleware': specifier: ^0.0.2 - version: 0.0.2(@ag-ui/client@0.0.47)(rxjs@7.8.1) + version: 0.0.2(@ag-ui/client@0.0.52)(rxjs@7.8.1) '@ag-ui/mcp-apps-middleware': specifier: ^0.0.3 - version: 0.0.3(@ag-ui/client@0.0.47)(@cfworker/json-schema@4.1.1)(hono@4.11.7)(zod@3.25.76) + version: 0.0.3(@ag-ui/client@0.0.52)(@cfworker/json-schema@4.1.1)(hono@4.11.7)(zod@3.25.76) '@copilotkit/react-core': - specifier: next - version: 1.54.0-next.6(@ag-ui/core@0.0.47)(@types/mdast@4.0.4)(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(graphql@16.12.0)(micromark-util-types@2.0.2)(micromark@4.0.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(signal-polyfill@0.2.2)(zod@3.25.76) + specifier: 1.55.2-next.1 + version: 1.55.2-next.1(@types/mdast@4.0.4)(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(graphql@16.12.0)(micromark-util-types@2.0.2)(micromark@4.0.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(zod@3.25.76) '@copilotkit/react-ui': - specifier: next - version: 1.54.0-next.6(@ag-ui/core@0.0.47)(@types/mdast@4.0.4)(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(graphql@16.12.0)(micromark-util-types@2.0.2)(micromark@4.0.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(signal-polyfill@0.2.2)(zod@3.25.76) + specifier: 1.55.2-next.1 + version: 1.55.2-next.1(@ag-ui/core@0.0.52)(@types/mdast@4.0.4)(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(graphql@16.12.0)(micromark-util-types@2.0.2)(micromark@4.0.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(zod@3.25.76) '@copilotkit/runtime': - specifier: next - version: 1.54.0-next.6(@ag-ui/encoder@0.0.47)(@cfworker/json-schema@4.1.1)(@copilotkitnext/shared@1.54.0-next.6)(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(@langchain/langgraph-sdk@1.5.5(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(ws@8.19.0) + specifier: 1.55.2-next.1 + version: 1.55.2-next.1(@cfworker/json-schema@4.1.1)(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(@langchain/langgraph-sdk@1.9.20(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@opentelemetry/api@1.9.0)(langchain@1.4.4(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(ws@8.19.0)(zod-to-json-schema@3.25.1(zod@3.25.76)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(zod-to-json-schema@3.25.1(zod@3.25.76)) '@copilotkitnext/shared': - specifier: next - version: 1.54.0-next.6 + specifier: 1.54.1-next.6 + version: 1.54.1-next.6 + '@repo/design-system': + specifier: workspace:* + version: link:../../packages/design-system next: specifier: 16.1.6 version: 16.1.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -66,6 +69,12 @@ importers: '@tailwindcss/postcss': specifier: ^4 version: 4.1.18 + '@testing-library/jest-dom': + specifier: ^6.9.1 + version: 6.9.1 + '@testing-library/react': + specifier: ^16.3.2 + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@types/node': specifier: ^20 version: 20.19.31 @@ -75,18 +84,27 @@ importers: '@types/react-dom': specifier: ^19 version: 19.2.3(@types/react@19.2.10) + '@vitejs/plugin-react': + specifier: ^6.0.2 + version: 6.0.2(vite@8.0.16(@types/node@20.19.31)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)) eslint: specifier: ^9 version: 9.39.2(jiti@2.6.1) eslint-config-next: specifier: 16.1.6 version: 16.1.6(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + jsdom: + specifier: ^29.1.1 + version: 29.1.1 tailwindcss: specifier: ^4 version: 4.1.18 typescript: specifier: ^5 version: 5.9.3 + vitest: + specifier: ^4.1.8 + version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@20.19.31)(jsdom@29.1.1)(vite@8.0.16(@types/node@20.19.31)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)) zod: specifier: ^3.23.8 version: 3.25.76 @@ -99,6 +117,9 @@ importers: '@modelcontextprotocol/sdk': specifier: ^1.25.3 version: 1.25.3(@cfworker/json-schema@4.1.1)(hono@4.11.7)(zod@3.25.76) + '@repo/design-system': + specifier: workspace:* + version: link:../../packages/design-system hono: specifier: ^4 version: 4.11.7 @@ -115,6 +136,21 @@ importers: typescript: specifier: ^5 version: 5.9.3 + vitest: + specifier: ^4.1.8 + version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@20.19.31)(jsdom@29.1.1)(vite@8.0.16(@types/node@20.19.31)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)) + + packages/design-system: + devDependencies: + '@types/node': + specifier: ^20 + version: 20.19.31 + typescript: + specifier: ^5 + version: 5.9.3 + vitest: + specifier: ^4.1.8 + version: 4.1.8(@opentelemetry/api@1.9.0)(@types/node@20.19.31)(jsdom@29.1.1)(vite@8.0.16(@types/node@20.19.31)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)) packages: @@ -126,8 +162,11 @@ packages: graphql: optional: true - '@a2ui/lit@0.8.1': - resolution: {integrity: sha512-QeqobciZz4OGMSgc2WGLFVidyhy+K7Z2GDpiuHN9NN+QlYMXByZqlzMvYPJsXrqf1lpQcMFRHgmUn1mwPpq9ew==} + '@a2ui/web_core@0.9.0': + resolution: {integrity: sha512-TsMWuEeuVDsScGIGPy/fWIZu+EOBRfhx6KwjKh3VwY1AwysRenQM8zDr8VrSk14Wck/aBgVxk2zWVrMCK2/s6A==} + + '@adobe/css-tools@4.5.0': + resolution: {integrity: sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==} '@ag-ui/a2ui-middleware@0.0.2': resolution: {integrity: sha512-dXHWlE9cYxFeQscPpvaLWpbeb7wXjnAlGYMId6kI7nMizSSIgHOrnNTugFRofYm78EY+yVgruNuDjDFWOmYj1A==} @@ -135,34 +174,52 @@ packages: '@ag-ui/client': '>=0.0.40' rxjs: 7.8.1 - '@ag-ui/client@0.0.47': - resolution: {integrity: sha512-zciVwYV6gmYzdMyWwSDR/VBcOj5x1lHPG/ZGDKyxDHbCeIdGp7sKoGORKHAiPAsfUhReGLKXsR/4IknqwY2PgQ==} + '@ag-ui/a2ui-middleware@0.0.4': + resolution: {integrity: sha512-N7goCObceqsCQgFRKBpo/X9D9Q0Jp6ALV+ier2W7WnK3sy0WfY2jAeFhqEaoZRqcNeLTKEt8sDqdtd4TGQE1+w==} + peerDependencies: + '@ag-ui/client': '>=0.0.40' + rxjs: 7.8.1 + + '@ag-ui/client@0.0.48': + resolution: {integrity: sha512-JAYH8gScC4JXxfsH8mfhfMzoQ/V0pUK2EapNCDa9TBpma2nraPNWFfxCneClhrk97Kb0wZCxviBKeJbvS++QGQ==} + + '@ag-ui/client@0.0.52': + resolution: {integrity: sha512-U407VvDDwR5qs8TiyN1qY38x87qMWc2n0epw8iA5aa1qwzCKBBDgg3Fkm4JogQf0X4jwNsz8HUbIZrBB56mrpg==} + + '@ag-ui/core@0.0.48': + resolution: {integrity: sha512-HP4wO+0+j8Rkshn0eiV0XAfrh7zeTbvZsQ2URopmMXVK3f6DC2I3jw3IN1ZGaJwSuzPtch5T3NC4jrj/PazVeA==} + + '@ag-ui/core@0.0.52': + resolution: {integrity: sha512-Xo0bUaNV56EqylzcrAuhUkQX7et7+SZIrqZZtEByGwEq/I1EHny6ZMkWHLkKR7UNi0FJZwJyhKYmKJS3B2SEgA==} - '@ag-ui/core@0.0.47': - resolution: {integrity: sha512-fHat7ZErAH028R90psYclTWaj6PdcvN2GJxzwWPF/j1c5ceqbF2+6xe+t06Psg+gCzZneI9QE3IkOkdJNplZ5A==} + '@ag-ui/encoder@0.0.48': + resolution: {integrity: sha512-tqfyZA6SLVibUi+KcBFRSfwLMUXkJ1qgn/FxqaJ0XK/LvfXW8RPREcKwPl1EWYHKJi3K3g7dvKlIFq4srbvn8A==} - '@ag-ui/encoder@0.0.47': - resolution: {integrity: sha512-AgKTM/DEHtaNrcbMa0z1UQ7lKiKtalbFAjBTTP0vCh+lJ6JWIu9LrpCJQ4EjON1IRoAZtJBORlCj1KY+F14HXQ==} + '@ag-ui/encoder@0.0.52': + resolution: {integrity: sha512-6GVDTb1dv2rjap7VVnmXYypDutZi6nrsTcdfxoP6ryDG5ynlXtmmS+FSDAt62JbIMD5CtEE963xNCb6d1iXw9g==} - '@ag-ui/langgraph@0.0.24': - resolution: {integrity: sha512-ebTYpUw28fvbmhqbpAbmfsDTfEqm1gSeZaBcnxMGHFivJLCzsJ/C9hYw6aV8yRKV3lMFBwh/QFxn1eRcr7yRkQ==} + '@ag-ui/langgraph@0.0.27': + resolution: {integrity: sha512-sfUG985ngG4HAGIZK04POvZVDrsI3QaeWuqJ388QgBPGg9n/oi4+vxueW7O5PIQv6uOPCLsbxf43pZZRN3zZtg==} peerDependencies: '@ag-ui/client': '>=0.0.42' '@ag-ui/core': '>=0.0.42' - '@ag-ui/mcp-apps-middleware@0.0.2': - resolution: {integrity: sha512-EMHm65hs3aNfoCpxZ1RYDLvZejmit0yipvzg39jwKrGTzqvB3CZuZUenDS9o2eWu2PZIvcFuvU15nEwH7SZb8A==} - peerDependencies: - '@ag-ui/client': '>=0.0.40' - rxjs: 7.8.1 - '@ag-ui/mcp-apps-middleware@0.0.3': resolution: {integrity: sha512-Z+NZQXj4J+Y/2PLNsiyhNzRWFtTT2sAoC5dztoAlIsdfzvLvYEa52YGdHesNTN85JJqaIrYxQ8e31IBpKjrnoA==} peerDependencies: '@ag-ui/client': '>=0.0.40' - '@ag-ui/proto@0.0.47': - resolution: {integrity: sha512-+KCrkeVeR6MulWoYUq9Fwm22gFlI9aKG50eKYRtbTM/Yuei/Che5vjbF297XfSnGUunzScrOmdnTeTCprrtb7A==} + '@ag-ui/proto@0.0.48': + resolution: {integrity: sha512-8kfOLdDRLg9B8I+eAlO/hqZ+iPPTqSYXrh9VN05cvLAEyoyeNE37A6XRDE1VBD+PevsCQmeJQDs2MfqY7UlDWQ==} + + '@ag-ui/proto@0.0.52': + resolution: {integrity: sha512-+iCGzNUNL50YIoThVmsolWPjG4MJidl+R9k8QAGVwErEfHRtQ64KFyrdpeOXNVuWtM3SViJqPSgFyv7eGVS63A==} + + '@ai-sdk/anthropic@2.0.81': + resolution: {integrity: sha512-0iqx9hZc9xqdhxOdZkYJAKuCs9o+5a86gStYl0M7IBZzmx6jTDrynXiOigDjH3SQrmLclLCspTjW5E6YFrlyHQ==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 '@ai-sdk/anthropic@3.0.58': resolution: {integrity: sha512-/53SACgmVukO4bkms4dpxpRlYhW8Ct6QZRe6sj1Pi5H00hYhxIrqfiLbZBGxkdRvjsBQeP/4TVGsXgH5rQeb8Q==} @@ -176,6 +233,18 @@ packages: peerDependencies: zod: ^3.25.76 || ^4.1.8 + '@ai-sdk/google-vertex@3.0.141': + resolution: {integrity: sha512-+PjbZu63x+7RABQpAnNcJ0+EEZjKt3nQESQszA4Gyv9rLajob+FvxRJWeiLcKDsGIQdEFBknDrI5KLLSm7Doeg==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + + '@ai-sdk/google@2.0.74': + resolution: {integrity: sha512-Lhw1742RXc+4pRIvqVXa0jdl5+qdpmw8lj0lm6OchUg9rVGHzymlaxe7CDiYX5U2af4jbjKeTY22LDi3bIycgQ==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + '@ai-sdk/google@3.0.43': resolution: {integrity: sha512-NGCgP5g8HBxrNdxvF8Dhww+UKfqAkZAmyYBvbu9YLoBkzAmGKDBGhVptN/oXPB5Vm0jggMdoLycZ8JReQM8Zqg==} engines: {node: '>=18'} @@ -188,18 +257,34 @@ packages: peerDependencies: zod: ^3.25.76 || ^4.1.8 + '@ai-sdk/openai-compatible@1.0.39': + resolution: {integrity: sha512-001hdQPPXxYBWrz5d+eAmBVYmwzsB+guIey1DFXi1ZEE5H3j7fRrhPpX55MdM9Fle2DS7WZ8b3qkumCIWE92YQ==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + '@ai-sdk/openai@3.0.41': resolution: {integrity: sha512-IZ42A+FO+vuEQCVNqlnAPYQnnUpUfdJIwn1BEDOBywiEHa23fw7PahxVtlX9zm3/zMvTW4JKPzWyvAgDu+SQ2A==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 + '@ai-sdk/provider-utils@3.0.25': + resolution: {integrity: sha512-CvsRu+32Y8a167s+lrIBtsybvgTHp8j9y+6BeTvLeoW3Q+okw/b4CnNUFOLIXsRaKHQKAH+IHNJPYWywfpw0LA==} + engines: {node: '>=18'} + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + '@ai-sdk/provider-utils@4.0.19': resolution: {integrity: sha512-3eG55CrSWCu2SXlqq2QCsFjo3+E7+Gmg7i/oRVoSZzIodTuDSfLb3MRje67xE9RFea73Zao7Lm4mADIfUETKGg==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 + '@ai-sdk/provider@2.0.3': + resolution: {integrity: sha512-h88OPkavHTiN9tMn2l5awAznGB0lXzjcLhgR1/rvjB2zlLprsNxbM2tt6OJsHUxduLC3klq0/eqaSf6fX5XVww==} + engines: {node: '>=18'} + '@ai-sdk/provider@3.0.8': resolution: {integrity: sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ==} engines: {node: '>=18'} @@ -211,6 +296,21 @@ packages: '@antfu/install-pkg@1.1.0': resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} + '@asamuzakjp/css-color@5.1.11': + resolution: {integrity: sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + '@asamuzakjp/dom-selector@7.1.1': + resolution: {integrity: sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + '@asamuzakjp/generational-cache@1.0.1': + resolution: {integrity: sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + '@asamuzakjp/nwsapi@2.3.9': + resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} + '@babel/code-frame@7.29.0': resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} @@ -285,6 +385,10 @@ packages: '@braintree/sanitize-url@7.1.2': resolution: {integrity: sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==} + '@bramus/specificity@2.4.2': + resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} + hasBin: true + '@bufbuild/protobuf@2.11.0': resolution: {integrity: sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ==} @@ -306,31 +410,38 @@ packages: '@chevrotain/utils@11.0.3': resolution: {integrity: sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==} - '@copilotkit/a2ui-renderer@1.54.0-next.6': - resolution: {integrity: sha512-zDdKieiCJXnRstdkcIXpw7rjpJxUXSuGDhwFsCfetcL17pSv+Dbon18rK8Qdku8v6FCCxouUlkunh6iHcSzc9Q==} + '@copilotkit/a2ui-renderer@1.55.2-next.1': + resolution: {integrity: sha512-6R/a07xAUMVuLczUZEapMhHIdurbP7u18+iiKkacn7LBJZwnSDM/CwkFENVKL1TeC/k73aPHN4JYrEdbVxt6vQ==} peerDependencies: react: ^18 || ^19 || ^19.0.0-rc react-dom: ^18 || ^19 || ^19.0.0-rc - '@copilotkit/react-core@1.54.0-next.6': - resolution: {integrity: sha512-F/KTUHDhelVS7YxMJ8LT5a6TLfYjh8p8GYOeYKokuL6vL1Eo51oz1GCm4u1ssqQbBb1cw0m0huiQB0nuD3o/mg==} + '@copilotkit/core@1.55.2-next.1': + resolution: {integrity: sha512-z8FfUtZrO8WP2ptPvzLbwPBakooqCVZjv5bHK347CNMHQabfSXR8r+bCsnYSYj8zbc9l9e2cLRdHgADPYh5A3A==} + engines: {node: '>=18'} + + '@copilotkit/license-verifier@0.0.1-a1': + resolution: {integrity: sha512-eTsupi14qPwDhpQBrFC6t4U5rxmHo9nPaHz60gOBPPCu7tTcA8GwEq5QfX/XGfmmKbCX2noL9yto1Pg0A8qQ9g==} + + '@copilotkit/react-core@1.55.2-next.1': + resolution: {integrity: sha512-NfvHwcK3EIdPg3fjfmCuRU2/N0CcRsNkqimg5KfXDd3bvXZesjX740vw65aHqrpthI2TYZMug/G7oZ/HpgTjmA==} peerDependencies: react: ^18 || ^19 || ^19.0.0-rc react-dom: ^18 || ^19 || ^19.0.0-rc zod: '>=3.0.0' - '@copilotkit/react-ui@1.54.0-next.6': - resolution: {integrity: sha512-FeQuhd926wK3aMIjWye+NgNLAyMawmFmHonyhMCF0TokPi7g3OPD0uUqNmcLZEk9bEXTwQp/7mZCM3lww0pBAw==} + '@copilotkit/react-ui@1.55.2-next.1': + resolution: {integrity: sha512-+i4HfwEGX90rISVZR1TNIHl15GQuko8qoZLISW4yEEY3HmS3BBtC625J2vhKXLLS0tqdEwVllxUrEVD8riPCjg==} peerDependencies: react: ^18 || ^19 || ^19.0.0-rc - '@copilotkit/runtime-client-gql@1.54.0-next.6': - resolution: {integrity: sha512-S3pD/kcZGbeVbcoL2j5KnPXwyCaOw5G6ayaL6blEfU7BeCJW+J2d1dF0unkpbg6POqtgcgKLl3SrRlCxkG0CIw==} + '@copilotkit/runtime-client-gql@1.55.2-next.1': + resolution: {integrity: sha512-7Rjw2uW09zIcwAw3vyalxjaYbV03OVbtnLAlbXpw2sLjs/FHRpsjIl1Bpv6KCcBt0sTC5rDrVNe+tyzVVCHO0A==} peerDependencies: react: ^18 || ^19 || ^19.0.0-rc - '@copilotkit/runtime@1.54.0-next.6': - resolution: {integrity: sha512-oNhKCJB6ojn50QEIer3NFH53WghuiZ1aYPPQ2F+S6nEgGoCNJwsbwckq3heAEKZ3SPV5Kek75ioeC0vuuESTxA==} + '@copilotkit/runtime@1.55.2-next.1': + resolution: {integrity: sha512-lCZK3wE3eaV7GJnnl+jFtCDOcOE3yAFPUh3cSK+QDfxK+RCsOVAC7fplUxbIolPngKsy//QL2UxKea7pPIKXUg==} peerDependencies: '@anthropic-ai/sdk': ^0.57.0 '@langchain/aws': '>=0.1.9' @@ -359,52 +470,74 @@ packages: langchain: optional: true - '@copilotkit/shared@1.54.0-next.6': - resolution: {integrity: sha512-q+FFUxibkpMtbvcuEeOhzdNsnhcN7YSLOsjy3kis5+NQnnCzfs4maNouELJ9LmkeLREiQ3pA1gw+tUOWPevXHw==} + '@copilotkit/shared@1.55.2-next.1': + resolution: {integrity: sha512-B96UNONgbJLL+pJr3smNkmFtaVMLQJLjjHmHQ7hprMVvwC5kjOxRC1HobhcrM/rwlspd/QPAYH6vKNzhir11jA==} peerDependencies: - '@ag-ui/core': ^0.0.47 + '@ag-ui/core': '>=0.0.48' - '@copilotkitnext/agent@1.54.0-next.6': - resolution: {integrity: sha512-lZVdGe/ESY+N+KXNxMXhazcso4eQh7bJzCMY2uAkROD/0/ihQ134Y/ZpDTlbSY/tgAtYTjJfc1INiuhEVz9FIA==} + '@copilotkit/web-inspector@1.55.2-next.1': + resolution: {integrity: sha512-gWZaSVEORqN3yavjK5987NYMiUuDseIk+W5ahcneKXQFZb7QRptU354AwXBpvPdZ5pVAXIht9xK3aUhivmfzrQ==} engines: {node: '>=18'} - '@copilotkitnext/core@1.54.0-next.6': - resolution: {integrity: sha512-OLL0O4Ql03OMD3E9ZrIxFyT5mFOy9f24nhvHqrUnRdsZRiU9WqytkzsV0cqB1h0yVz4siI5Tj+W2jmpHb/agzQ==} + '@copilotkitnext/shared@1.54.1-next.6': + resolution: {integrity: sha512-jYTkGpdN5CIe7W6xNBOfXPAFdVzpW2UIM18eotF6QF7rFneWYcI3GTl8FaCIhLFN1bjdVjCqRLaVr2EmkCJJig==} engines: {node: '>=18'} + deprecated: This package is deprecated. Use @copilotkit/shared instead. V2 features are being integrated into the main @copilotkit exports and will be available under the /v2 subpath. - '@copilotkitnext/react@1.54.0-next.6': - resolution: {integrity: sha512-pV+NcGyzc5mYY3cqXAZ6LUSAiizi6xY5U4/U3S+XFUIkezuchJ+67Fj7I074l2f21k5yVhyqLgAmAXtCRGI3aA==} - engines: {node: '>=18'} + '@csstools/color-helpers@6.0.2': + resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==} + engines: {node: '>=20.19.0'} + + '@csstools/css-calc@3.2.1': + resolution: {integrity: sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg==} + engines: {node: '>=20.19.0'} peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 - '@copilotkitnext/runtime@1.54.0-next.6': - resolution: {integrity: sha512-MMaH+LI0lpMqH8RPG8H35nfTk2iuXf48lf0+DD4nmQQXJKHT2Ht2J3Y6i9t2JA+084IvRk7XDNkLpDqkZMqDHA==} - engines: {node: '>=18'} + '@csstools/css-color-parser@4.1.2': + resolution: {integrity: sha512-n6Zd8mpVhObnaOqq6TC/lBCKgYncAGfFwuvJGQZTDRAwEoxwXIZu9kXBQeXkcqHsE6Sp6LyxDMrvXj5gOxnryw==} + engines: {node: '>=20.19.0'} peerDependencies: - '@ag-ui/client': 0.0.47 - '@ag-ui/core': 0.0.47 - '@ag-ui/encoder': 0.0.47 - '@copilotkitnext/shared': 1.54.0-next.6 + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 - '@copilotkitnext/shared@1.54.0-next.6': - resolution: {integrity: sha512-QzbNBcNgxrzfQ7XtB1dj7FRoQGoKqkAIBWXG5UmiUYANFEfOaS5ESE1tyCtE93ArmpJKHLKJtgKDuNEbBR/Plg==} - engines: {node: '>=18'} + '@csstools/css-parser-algorithms@4.0.0': + resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-tokenizer': ^4.0.0 - '@copilotkitnext/web-inspector@1.54.0-next.6': - resolution: {integrity: sha512-KlEaypFWRk1wOZlpDEkfvxanxRpQoLOEFizMzShBSSd7/rzoctbq5DTKBO37ZE3ewsXxpaHqgeurIHo6O4nHGg==} - engines: {node: '>=18'} + '@csstools/css-syntax-patches-for-csstree@1.1.5': + resolution: {integrity: sha512-oNjBvzLq2GPZtJphCjLqXow/cHySHSgtxvKZb7OqSZ/xHgw6NWNhfad+6AB9cLeVm6eA9d/qMll3JdEHjy6M+A==} + peerDependencies: + css-tree: ^3.2.1 + peerDependenciesMeta: + css-tree: + optional: true + + '@csstools/css-tokenizer@4.0.0': + resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} + engines: {node: '>=20.19.0'} + + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} '@emnapi/core@1.8.1': resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + '@emnapi/runtime@1.8.1': resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + '@envelop/core@5.5.0': resolution: {integrity: sha512-nsU1EyJQAStaKHR1ZkB/ug9XBm+WPTliYtdedbJ/L1ykrp7dbbn0srqBeDnZ2mbZVp4hH3d0Fy+Og9OgPWZx+g==} engines: {node: '>=18.0.0'} @@ -611,6 +744,15 @@ packages: resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@exodus/bytes@1.15.1': + resolution: {integrity: sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@noble/hashes': ^1.8.0 || ^2.0.0 + peerDependenciesMeta: + '@noble/hashes': + optional: true + '@fastify/busboy@3.2.0': resolution: {integrity: sha512-m9FVDXU3GT2ITSe0UaMA5rU3QkfC/UXtCU8y0gSN/GugTqtVldOBWIB5V6V3sbmenVZUIpU6f+mPEO2+m5iTaA==} @@ -861,6 +1003,9 @@ packages: cpu: [x64] os: [win32] + '@jetbrains/websandbox@1.2.1': + resolution: {integrity: sha512-FXg2JZ4O4DPf3Tj3MGwnQuJ8jEzddqEZszBEVD4SFPkq44FrbLomS7BLY3Q3eKV312oQRJU9api1YvX3uhNelw==} + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -881,6 +1026,12 @@ packages: resolution: {integrity: sha512-vcJDV2vk1AlCwSh3aBm/urQ1ZrlXFFBocv11bz/NBUfLWD5/UDNMzwPdaAd2dKvNmTWa9FM2lirLU3+JCf4cRA==} engines: {node: '>=18'} + '@langchain/langgraph-checkpoint@1.0.4': + resolution: {integrity: sha512-1y5MgZ0gXXrtmoy56e3kaBChI3GwFPIKl27xkrHwN+VE/3iUsyr9gO3Jtp7kdKAe6diZGbcas5bdC/r0yUwTZA==} + engines: {node: '>=18'} + peerDependencies: + '@langchain/core': ^1.1.44 + '@langchain/langgraph-sdk@0.1.10': resolution: {integrity: sha512-9srSCb2bSvcvehMgjA2sMMwX0o1VUgPN6ghwm5Fwc9JGAKsQa6n1S4eCwy1h4abuYxwajH5n3spBw+4I2WYbgw==} peerDependencies: @@ -895,32 +1046,44 @@ packages: react-dom: optional: true - '@langchain/langgraph-sdk@1.5.5': - resolution: {integrity: sha512-SyiAs6TVXPWlt/8cI9pj/43nbIvclY3ytKqUFbL5MplCUnItetEyqvH87EncxyVF5D7iJKRZRfSVYBMmOZbjbQ==} + '@langchain/langgraph-sdk@1.9.20': + resolution: {integrity: sha512-waZQNUN6apVg3jvDApy16wUGwrCvJB8WXHbIPvVrrUZHObqx0w5tk7P/Ite5Qvu4abWrvNtrmqk2zmcqCx7jVw==} peerDependencies: - '@langchain/core': ^1.1.15 + '@langchain/core': ^1.1.48 react: ^18 || ^19 react-dom: ^18 || ^19 + svelte: ^4.0.0 || ^5.0.0 + vue: ^3.0.0 peerDependenciesMeta: - '@langchain/core': - optional: true react: optional: true react-dom: optional: true + svelte: + optional: true + vue: + optional: true + + '@langchain/langgraph@1.3.7': + resolution: {integrity: sha512-6WNskiu3bpy3XFwiD9cm4n2QapnFVX7dqYeJzuEAUGp9R3vbxngRVyb5+Myp5Rz4GCFXGXuhcFSjLVRHPhsNtQ==} + engines: {node: '>=18'} + peerDependencies: + '@langchain/core': ^1.1.48 + zod: ^3.25.32 || ^4.2.0 + zod-to-json-schema: ^3.x + peerDependenciesMeta: + zod-to-json-schema: + optional: true + + '@langchain/protocol@0.0.16': + resolution: {integrity: sha512-ws+J7MaHyhO5dG7f0vdyHQiUn9hoCnki0f3crJPa4MCTGzcRC39jYSCghyrGtBPYQnZbUQiGyRVpW3z3M8IpJg==} '@lit-labs/react@2.1.3': resolution: {integrity: sha512-OD9h2JynerBQUMNzb563jiVpxfvPF0HjQkKY2mx0lpVYvD7F+rtJpOGz6ek+6ufMidV3i+MPT9SX62OKWHFrQg==} - '@lit-labs/signals@0.1.3': - resolution: {integrity: sha512-P0yWgH5blwVyEwBg+WFspLzeu1i0ypJP1QB0l1Omr9qZLIPsUu0p4Fy2jshOg7oQyha5n163K3GJGeUhQQ682Q==} - '@lit-labs/ssr-dom-shim@1.5.1': resolution: {integrity: sha512-Aou5UdlSpr5whQe8AA/bZG0jMj96CoJIWbGfZ91qieWu5AWUMKw8VR/pAkQkJYvBNhmCcWnZlyyk5oze8JIqYA==} - '@lit/context@1.1.6': - resolution: {integrity: sha512-M26qDE6UkQbZA2mQ3RjJ3Gzd8TxP+/0obMgE5HfkfLhEEyYE3Bui4A5XHiGPjy0MUGAyxB3QgVuw2ciS0kHn6A==} - '@lit/react@1.0.8': resolution: {integrity: sha512-p2+YcF+JE67SRX3mMlJ1TKCSTsgyOVdAwd/nxp3NuV1+Cb6MWALbN6nT7Ld4tpmYofcE5kcaSY1YBB9erY+6fw==} peerDependencies: @@ -953,6 +1116,12 @@ packages: '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} + '@napi-rs/wasm-runtime@1.1.5': + resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + '@next/env@16.1.6': resolution: {integrity: sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==} @@ -1027,9 +1196,15 @@ packages: resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} engines: {node: '>=8.0.0'} + '@oxc-project/types@0.133.0': + resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==} + '@pinojs/redact@0.4.0': resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} + '@preact/signals-core@1.14.2': + resolution: {integrity: sha512-RZHdBj9ZF4n40Rp4jS052EHHjBWf96P9oNdXPfhQTovCuWY9iQn3Gq+gOTJSgBO9A/JBuPfMOWsSX/lIU9Pc/A==} + '@protobuf-ts/protoc@2.11.1': resolution: {integrity: sha512-mUZJaV0daGO6HUX90o/atzQ6A7bbN2RSuHtdwo8SSF2Qoe3zHwa4IHyCN1evftTeHfLmdz+45qo47sL+5P8nyg==} hasBin: true @@ -1383,9 +1558,104 @@ packages: react-redux: optional: true + '@remix-run/node-fetch-server@0.13.3': + resolution: {integrity: sha512-UfjOXed/DQteaM5VyTfqTeGpHwyL2J5aoRGY6cydip4tt1ehNNeSwuXCC7AEGE0RWBs/7bgKxYkL/B/+UDe4AA==} + '@repeaterjs/repeater@3.0.6': resolution: {integrity: sha512-Javneu5lsuhwNCryN+pXH93VPQ8g0dBX7wItHFgYiwQmzE1sVdg5tWHiOgHywzL2W21XQopa7IwIEnNbmeUJYA==} + '@rolldown/binding-android-arm64@1.0.3': + resolution: {integrity: sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.3': + resolution: {integrity: sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.3': + resolution: {integrity: sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.3': + resolution: {integrity: sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + resolution: {integrity: sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.3': + resolution: {integrity: sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-arm64-musl@1.0.3': + resolution: {integrity: sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-ppc64-gnu@1.0.3': + resolution: {integrity: sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + + '@rolldown/binding-linux-s390x-gnu@1.0.3': + resolution: {integrity: sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + + '@rolldown/binding-linux-x64-gnu@1.0.3': + resolution: {integrity: sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-linux-x64-musl@1.0.3': + resolution: {integrity: sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-openharmony-arm64@1.0.3': + resolution: {integrity: sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.3': + resolution: {integrity: sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.3': + resolution: {integrity: sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.3': + resolution: {integrity: sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} @@ -1532,9 +1802,41 @@ packages: '@tanstack/virtual-core@3.13.18': resolution: {integrity: sha512-Mx86Hqu1k39icq2Zusq+Ey2J6dDWTjDvEv43PJtRCoEYTLyfaPnxIQ6iy7YAOK0NV/qOEmZQ/uCufrppZxTgcg==} + '@testing-library/dom@10.4.1': + resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} + engines: {node: '>=18'} + + '@testing-library/jest-dom@6.9.1': + resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==} + engines: {node: '>=14', npm: '>=6', yarn: '>=1'} + + '@testing-library/react@16.3.2': + resolution: {integrity: sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==} + engines: {node: '>=18'} + peerDependencies: + '@testing-library/dom': ^10.0.0 + '@types/react': ^18.0.0 || ^19.0.0 + '@types/react-dom': ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@tybys/wasm-util@0.10.2': + resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} + + '@types/aria-query@5.0.4': + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + '@types/d3-array@3.2.2': resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} @@ -1631,6 +1933,9 @@ packages: '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + '@types/estree-jsx@1.0.5': resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} @@ -1769,6 +2074,7 @@ packages: '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + deprecated: Potential CWE-502 - Update to 1.3.1 or higher '@unrs/resolver-binding-android-arm-eabi@1.11.1': resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} @@ -1872,6 +2178,48 @@ packages: resolution: {integrity: sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==} engines: {node: '>= 20'} + '@vitejs/plugin-react@6.0.2': + resolution: {integrity: sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0 + babel-plugin-react-compiler: ^1.0.0 + vite: ^8.0.0 + peerDependenciesMeta: + '@rolldown/plugin-babel': + optional: true + babel-plugin-react-compiler: + optional: true + + '@vitest/expect@4.1.8': + resolution: {integrity: sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==} + + '@vitest/mocker@4.1.8': + resolution: {integrity: sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@4.1.8': + resolution: {integrity: sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==} + + '@vitest/runner@4.1.8': + resolution: {integrity: sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==} + + '@vitest/snapshot@4.1.8': + resolution: {integrity: sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==} + + '@vitest/spy@4.1.8': + resolution: {integrity: sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==} + + '@vitest/utils@4.1.8': + resolution: {integrity: sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==} + '@whatwg-node/disposablestack@0.0.6': resolution: {integrity: sha512-LOtTn+JgJvX8WfBVJtF08TGrdjuFzGJc4mkP8EdDI8ADbvO7kiexYep1o8dwnt0okb0jYclCDXF13xU7Ge4zSw==} engines: {node: '>=18.0.0'} @@ -1918,6 +2266,10 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + agentkeepalive@4.6.0: resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} engines: {node: '>= 8.0.0'} @@ -1961,6 +2313,9 @@ packages: resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} engines: {node: '>=10'} + aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + aria-query@5.3.2: resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} engines: {node: '>= 0.4'} @@ -2000,6 +2355,10 @@ packages: resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} engines: {node: '>= 0.4'} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + ast-types-flow@0.0.8: resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} @@ -2039,6 +2398,12 @@ packages: resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==} hasBin: true + bidi-js@1.0.3: + resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + + bignumber.js@9.3.1: + resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} + body-parser@1.20.4: resolution: {integrity: sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} @@ -2062,6 +2427,9 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} @@ -2095,6 +2463,10 @@ packages: ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -2128,6 +2500,10 @@ packages: chevrotain@11.0.3: resolution: {integrity: sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==} + clarinet@0.12.6: + resolution: {integrity: sha512-0FR+TrvLbYHLjhzs9oeIbd3yfZmd4u2DzYQEjUTm2dNfh4Y/9RIRWPjsm3aBtrVEpjKI7+lWa4ouqEXoml84mQ==} + engines: {chrome: '>=16.0.912', firefox: '>=0.8.0', node: '>=0.3.6'} + class-transformer@0.5.1: resolution: {integrity: sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==} @@ -2244,6 +2620,13 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + css-tree@3.2.1: + resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + + css.escape@1.5.1: + resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} + csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} @@ -2406,6 +2789,14 @@ packages: damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + + data-urls@7.0.0: + resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + data-view-buffer@1.0.2: resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} engines: {node: '>= 0.4'} @@ -2418,6 +2809,9 @@ packages: resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} engines: {node: '>= 0.4'} + date-fns@4.4.0: + resolution: {integrity: sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==} + dateformat@4.6.3: resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} @@ -2456,6 +2850,9 @@ packages: decimal.js-light@2.5.1: resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + decode-named-character-reference@1.3.0: resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} @@ -2507,6 +2904,12 @@ packages: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} + dom-accessibility-api@0.5.16: + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + + dom-accessibility-api@0.6.3: + resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} + dompurify@3.3.1: resolution: {integrity: sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==} @@ -2518,6 +2921,9 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} + ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -2541,14 +2947,14 @@ packages: resolution: {integrity: sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==} engines: {node: '>=10.13.0'} - entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} - entities@6.0.1: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} + entities@8.0.0: + resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==} + engines: {node: '>=20.19.0'} + es-abstract@1.24.1: resolution: {integrity: sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==} engines: {node: '>= 0.4'} @@ -2565,6 +2971,9 @@ packages: resolution: {integrity: sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w==} engines: {node: '>= 0.4'} + es-module-lexer@2.1.0: + resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} + es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} @@ -2719,6 +3128,9 @@ packages: estree-util-is-identifier-name@3.0.0: resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} @@ -2749,6 +3161,10 @@ packages: resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} engines: {node: '>=18.0.0'} + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} + express-rate-limit@7.5.1: resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==} engines: {node: '>= 16'} @@ -2806,6 +3222,10 @@ packages: picomatch: optional: true + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -2852,6 +3272,10 @@ packages: resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==} engines: {node: '>= 12.20'} + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} @@ -2879,6 +3303,14 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + gaxios@7.1.5: + resolution: {integrity: sha512-5FZy72Rh8LhtjmvDrKkI+lVhrsQrVKVsItxMoDm5mNQE+xR0WVIIs+jzPSJgBvKVsLi24fZhXJIsNI0bihDzFg==} + engines: {node: '>=18'} + + gcp-metadata@8.1.2: + resolution: {integrity: sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==} + engines: {node: '>=18'} + generator-function@2.0.1: resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} engines: {node: '>= 0.4'} @@ -2934,6 +3366,14 @@ packages: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} + google-auth-library@10.7.0: + resolution: {integrity: sha512-QpTAbNJ36TliZLx3TTtahR8HG0hN9RllL1e3FymOvQSIKK8JmgV58H924ub2wa2DsS3ANjjP1Aw1N+Ramc8hqQ==} + engines: {node: '>=18'} + + google-logging-utils@1.1.3: + resolution: {integrity: sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==} + engines: {node: '>=14'} + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -3066,6 +3506,10 @@ packages: resolution: {integrity: sha512-l7qMiNee7t82bH3SeyUCt9UF15EVmaBvsppY2zQtrbIhl/yzBTny+YUxsVjSjQ6gaqaeVtZmGocom8TzBlA4Yw==} engines: {node: '>=16.9.0'} + html-encoding-sniffer@6.0.0: + resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + html-url-attributes@3.0.1: resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==} @@ -3076,6 +3520,10 @@ packages: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + humanize-ms@1.2.1: resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} @@ -3116,6 +3564,10 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -3247,6 +3699,9 @@ packages: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-promise@4.0.0: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} @@ -3320,11 +3775,23 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true + jsdom@29.1.1: + resolution: {integrity: sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0} + peerDependencies: + canvas: ^3.0.0 + peerDependenciesMeta: + canvas: + optional: true + jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} hasBin: true + json-bigint@1.0.0: + resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} + json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -3356,6 +3823,12 @@ packages: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} + jwa@2.0.1: + resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} + + jws@4.0.1: + resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} + katex@0.16.28: resolution: {integrity: sha512-YHzO7721WbmAL6Ov1uzN/l5mY5WWWhJBSW+jq4tkfZfsxmo1hu6frS0EOswvjBUnWE6NtjEs48SFn5CQESRLZg==} hasBin: true @@ -3370,6 +3843,12 @@ packages: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} + langchain@1.4.4: + resolution: {integrity: sha512-tepOCwUDaIZOYJ9Eo0O6o5dXEN/0KJheiFDnHHFL8Tx8rfkDLL4cOTSTln4Vpn9LpWzXYkjQ8lkHnnNDQWZPeg==} + engines: {node: '>=20'} + peerDependencies: + '@langchain/core': ^1.1.48 + langium@3.3.1: resolution: {integrity: sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==} engines: {node: '>=16.0.0'} @@ -3391,6 +3870,26 @@ packages: openai: optional: true + langsmith@0.7.6: + resolution: {integrity: sha512-6IRm+sAxHT2n5GAZbqEnUzkhOu3Q8vqQtMiOpYfGiI+pxUe/fYQSzV0Pr7q5x9JD8bnZ8xK2/P9dhPHs4zO/Nw==} + peerDependencies: + '@opentelemetry/api': '*' + '@opentelemetry/exporter-trace-otlp-proto': '*' + '@opentelemetry/sdk-trace-base': '*' + openai: '*' + ws: '>=7' + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@opentelemetry/exporter-trace-otlp-proto': + optional: true + '@opentelemetry/sdk-trace-base': + optional: true + openai: + optional: true + ws: + optional: true + language-subtag-registry@0.3.23: resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} @@ -3417,72 +3916,139 @@ packages: cpu: [arm64] os: [android] + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + lightningcss-darwin-arm64@1.30.2: resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + lightningcss-darwin-x64@1.30.2: resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + lightningcss-freebsd-x64@1.30.2: resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + lightningcss-linux-arm-gnueabihf@1.30.2: resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + lightningcss-linux-arm64-gnu@1.30.2: resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + lightningcss-linux-arm64-musl@1.30.2: resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + lightningcss-linux-x64-gnu@1.30.2: resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + lightningcss-linux-x64-musl@1.30.2: resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + lightningcss-win32-arm64-msvc@1.30.2: resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + lightningcss-win32-x64-msvc@1.30.2: resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + lightningcss@1.30.2: resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} engines: {node: '>= 12.0.0'} - linkify-it@5.0.0: - resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} lit-element@4.2.2: resolution: {integrity: sha512-aFKhNToWxoyhkNDmWZwEva2SlQia+jfG0fjIWV//YeTaWrVnOxD89dPKfigCUspXFmjzOEUQpOkejH5Ly6sG0w==} @@ -3523,6 +4089,10 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@11.5.1: + resolution: {integrity: sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==} + engines: {node: 20 || >=22} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -3539,13 +4109,13 @@ packages: lucide@0.525.0: resolution: {integrity: sha512-sfehWlaE/7NVkcEQ4T9JD3eID8RNMIGJBBUq9wF3UFiJIrcMKRbU3g1KGfDk4svcW7yw8BtDLXaXo02scDtUYQ==} + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - markdown-it@14.1.1: - resolution: {integrity: sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==} - hasBin: true - markdown-table@3.0.4: resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} @@ -3623,8 +4193,8 @@ packages: mdast-util-to-string@4.0.0: resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} - mdurl@2.0.0: - resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + mdn-data@2.27.1: + resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} media-typer@0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} @@ -3856,6 +4426,10 @@ packages: engines: {node: '>=4'} hasBin: true + min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -3888,6 +4462,11 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + napi-postinstall@0.3.4: resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} @@ -3939,6 +4518,10 @@ packages: encoding: optional: true + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + node-releases@2.0.27: resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} @@ -3974,6 +4557,10 @@ packages: resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} + obug@2.1.2: + resolution: {integrity: sha512-AWGB9WFcRXOQs48Z/udjI5ZcZMHXwX8XPByNpOydgcGsDLIzjGizhoMWJyKAWze7AVW/2W1i+/gPX4YtKe5cyg==} + engines: {node: '>=12.20.0'} + on-exit-leak-free@2.1.2: resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} engines: {node: '>=14.0.0'} @@ -4063,6 +4650,9 @@ packages: parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + parse5@8.0.1: + resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==} + parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -4103,8 +4693,8 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} pino-abstract-transport@2.0.0: @@ -4142,6 +4732,10 @@ packages: resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} engines: {node: ^10 || ^12 || >=14} + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + engines: {node: ^10 || ^12 || >=14} + postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} @@ -4150,6 +4744,10 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + prismjs@1.27.0: resolution: {integrity: sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==} engines: {node: '>=6'} @@ -4184,10 +4782,6 @@ packages: pump@3.0.3: resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} - punycode.js@2.3.1: - resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} - engines: {node: '>=6'} - punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -4239,6 +4833,9 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} @@ -4332,6 +4929,10 @@ packages: react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-is: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + redent@3.0.0: + resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} + engines: {node: '>=8'} + redux-thunk@3.1.0: resolution: {integrity: sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==} peerDependencies: @@ -4457,6 +5058,11 @@ packages: robust-predicates@3.0.2: resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + rolldown@1.0.3: + resolution: {integrity: sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + roughjs@4.6.6: resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} @@ -4502,6 +5108,10 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} @@ -4583,13 +5193,8 @@ packages: resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} engines: {node: '>= 0.4'} - signal-polyfill@0.2.2: - resolution: {integrity: sha512-p63Y4Er5/eMQ9RHg0M0Y64NlsQKpiu6MDdhBXpyywRuWiPywhJTpKJ1iB5K2hJEbFZ0BnDS7ZkJ+0AfTuL37Rg==} - - signal-utils@0.21.1: - resolution: {integrity: sha512-i9cdLSvVH4j8ql8mz2lyrA93xL499P8wEbIev3ldSriXeUwqh+wM4Q5VPhIZ19gPtIS4BOopJuKB8l1+wH9LCg==} - peerDependencies: - signal-polyfill: ^0.2.0 + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} simple-wcswidth@1.1.2: resolution: {integrity: sha512-j7piyCjAeTDSjzTSQ7DokZtMNwNlEAyxqSZeCS+CXH7fJ4jx3FuJ/mTW3mE+6JLs4VJBbcll0Kjn+KXI5t21Iw==} @@ -4614,10 +5219,16 @@ packages: stable-hash@0.0.5: resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + statuses@2.0.2: resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} engines: {node: '>= 0.8'} + std-env@4.1.0: + resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} + stop-iteration-iterator@1.1.0: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} @@ -4668,6 +5279,10 @@ packages: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} + strip-indent@3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -4709,6 +5324,9 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + tabbable@6.4.0: resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} @@ -4728,6 +5346,9 @@ packages: tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + tinyexec@1.0.2: resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} engines: {node: '>=18'} @@ -4736,6 +5357,21 @@ packages: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + tinyrainbow@3.1.0: + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} + engines: {node: '>=14.0.0'} + + tldts-core@7.4.2: + resolution: {integrity: sha512-nwEyF4vl4RSJjwSjBUmOSxc3BFPoIFdlRthJ6e+5v9P3bHNsoD06UjuqMUspqp7vsEZ1beaHi1km+optiE17yA==} + + tldts@7.4.2: + resolution: {integrity: sha512-kCwffuaH8ntKtygnWe1b4BJKWiCUH30n5KfoTr6IchcXOwR7chAOFJxFrH3vjANafUYrIA4a7SDL+nn7SiR4Sw==} + hasBin: true + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -4747,9 +5383,17 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} + tough-cookie@6.0.1: + resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==} + engines: {node: '>=16'} + tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + tr46@6.0.0: + resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} + engines: {node: '>=20'} + tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -4770,10 +5414,6 @@ packages: resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} engines: {node: '>=6.10'} - ts-deepmerge@7.0.3: - resolution: {integrity: sha512-Du/ZW2RfwV/D4cmA5rXafYjBQVuvu4qGiEEla4EmEHVHgRdx68Gftx7i66jn2bzHPwSVZY36Ae6OuDn9el4ZKA==} - engines: {node: '>=14.13.1'} - tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} @@ -4876,9 +5516,6 @@ packages: engines: {node: '>=14.17'} hasBin: true - uc.micro@2.1.0: - resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} - ufo@1.6.3: resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} @@ -4892,6 +5529,10 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici@7.27.2: + resolution: {integrity: sha512-uZsKNuzQxDMUY6M3pIMvy5tvlGmtq8XJ2oLAkfRKGNu+1VQAIvLy2xIVG5ATZl5wDXl/tddByAWCizRbOme+TA==} + engines: {node: '>=20.18.1'} + unified@10.1.2: resolution: {integrity: sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==} @@ -5001,18 +5642,20 @@ packages: uuid@10.0.0: resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true uuid@11.1.0: resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} hasBin: true - uuid@13.0.0: - resolution: {integrity: sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==} + uuid@14.0.0: + resolution: {integrity: sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==} hasBin: true uuid@9.0.1: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true uvu@0.5.6: @@ -5046,6 +5689,90 @@ packages: victory-vendor@37.3.6: resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==} + vite@8.0.16: + resolution: {integrity: sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.18 + esbuild: ^0.27.3 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@4.1.8: + resolution: {integrity: sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.1.8 + '@vitest/browser-preview': 4.1.8 + '@vitest/browser-webdriverio': 4.1.8 + '@vitest/coverage-istanbul': 4.1.8 + '@vitest/coverage-v8': 4.1.8 + '@vitest/ui': 4.1.8 + happy-dom: '*' + jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + vscode-jsonrpc@8.2.0: resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} engines: {node: '>=14.0.0'} @@ -5066,9 +5793,17 @@ packages: vscode-uri@3.0.8: resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} + w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} + web-namespaces@2.0.1: resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + web-streams-polyfill@4.0.0-beta.3: resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==} engines: {node: '>= 14'} @@ -5076,6 +5811,18 @@ packages: webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + webidl-conversions@8.0.1: + resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} + engines: {node: '>=20'} + + whatwg-mimetype@5.0.0: + resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} + engines: {node: '>=20'} + + whatwg-url@16.0.1: + resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -5100,6 +5847,11 @@ packages: engines: {node: '>= 8'} hasBin: true + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + wonka@6.3.5: resolution: {integrity: sha512-SSil+ecw6B4/Dm7Pf2sAshKQ5hWFvfyGlfPbEd6A14dOH6VDjrmbY86u6nZvy9omGwwIPFR8V41+of1EezgoUw==} @@ -5126,6 +5878,13 @@ packages: utf-8-validate: optional: true + xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} @@ -5172,26 +5931,44 @@ snapshots: optionalDependencies: graphql: 16.12.0 - '@a2ui/lit@0.8.1(signal-polyfill@0.2.2)': + '@a2ui/web_core@0.9.0': dependencies: - '@lit-labs/signals': 0.1.3 - '@lit/context': 1.1.6 - lit: 3.3.2 - markdown-it: 14.1.1 - signal-utils: 0.21.1(signal-polyfill@0.2.2) - transitivePeerDependencies: - - signal-polyfill + '@preact/signals-core': 1.14.2 + date-fns: 4.4.0 + zod: 3.25.76 + zod-to-json-schema: 3.25.1(zod@3.25.76) - '@ag-ui/a2ui-middleware@0.0.2(@ag-ui/client@0.0.47)(rxjs@7.8.1)': + '@adobe/css-tools@4.5.0': {} + + '@ag-ui/a2ui-middleware@0.0.2(@ag-ui/client@0.0.52)(rxjs@7.8.1)': dependencies: - '@ag-ui/client': 0.0.47 + '@ag-ui/client': 0.0.52 + rxjs: 7.8.1 + + '@ag-ui/a2ui-middleware@0.0.4(@ag-ui/client@0.0.52)(rxjs@7.8.1)': + dependencies: + '@ag-ui/client': 0.0.52 + clarinet: 0.12.6 + rxjs: 7.8.1 + + '@ag-ui/client@0.0.48': + dependencies: + '@ag-ui/core': 0.0.48 + '@ag-ui/encoder': 0.0.48 + '@ag-ui/proto': 0.0.48 + '@types/uuid': 10.0.0 + compare-versions: 6.1.1 + fast-json-patch: 3.1.1 rxjs: 7.8.1 + untruncate-json: 0.0.1 + uuid: 11.1.0 + zod: 3.25.76 - '@ag-ui/client@0.0.47': + '@ag-ui/client@0.0.52': dependencies: - '@ag-ui/core': 0.0.47 - '@ag-ui/encoder': 0.0.47 - '@ag-ui/proto': 0.0.47 + '@ag-ui/core': 0.0.52 + '@ag-ui/encoder': 0.0.52 + '@ag-ui/proto': 0.0.52 '@types/uuid': 10.0.0 compare-versions: 6.1.1 fast-json-patch: 3.1.1 @@ -5200,22 +5977,32 @@ snapshots: uuid: 11.1.0 zod: 3.25.76 - '@ag-ui/core@0.0.47': + '@ag-ui/core@0.0.48': dependencies: rxjs: 7.8.1 zod: 3.25.76 - '@ag-ui/encoder@0.0.47': + '@ag-ui/core@0.0.52': + dependencies: + zod: 3.25.76 + + '@ag-ui/encoder@0.0.48': + dependencies: + '@ag-ui/core': 0.0.48 + '@ag-ui/proto': 0.0.48 + + '@ag-ui/encoder@0.0.52': dependencies: - '@ag-ui/core': 0.0.47 - '@ag-ui/proto': 0.0.47 + '@ag-ui/core': 0.0.52 + '@ag-ui/proto': 0.0.52 - '@ag-ui/langgraph@0.0.24(@ag-ui/client@0.0.47)(@ag-ui/core@0.0.47)(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@ag-ui/langgraph@0.0.27(@ag-ui/client@0.0.52)(@ag-ui/core@0.0.52)(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(ws@8.19.0)(zod-to-json-schema@3.25.1(zod@3.25.76))': dependencies: - '@ag-ui/client': 0.0.47 - '@ag-ui/core': 0.0.47 + '@ag-ui/client': 0.0.52 + '@ag-ui/core': 0.0.52 '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)) '@langchain/langgraph-sdk': 0.1.10(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + langchain: 1.4.4(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(ws@8.19.0)(zod-to-json-schema@3.25.1(zod@3.25.76)) partial-json: 0.1.7 rxjs: 7.8.1 transitivePeerDependencies: @@ -5225,10 +6012,14 @@ snapshots: - openai - react - react-dom + - svelte + - vue + - ws + - zod-to-json-schema - '@ag-ui/mcp-apps-middleware@0.0.2(@ag-ui/client@0.0.47)(@cfworker/json-schema@4.1.1)(hono@4.11.7)(rxjs@7.8.1)(zod@3.25.76)': + '@ag-ui/mcp-apps-middleware@0.0.3(@ag-ui/client@0.0.52)(@cfworker/json-schema@4.1.1)(hono@4.11.7)(zod@3.25.76)': dependencies: - '@ag-ui/client': 0.0.47 + '@ag-ui/client': 0.0.52 '@modelcontextprotocol/sdk': 1.25.3(@cfworker/json-schema@4.1.1)(hono@4.11.7)(zod@3.25.76) rxjs: 7.8.1 transitivePeerDependencies: @@ -5237,23 +6028,24 @@ snapshots: - supports-color - zod - '@ag-ui/mcp-apps-middleware@0.0.3(@ag-ui/client@0.0.47)(@cfworker/json-schema@4.1.1)(hono@4.11.7)(zod@3.25.76)': + '@ag-ui/proto@0.0.48': dependencies: - '@ag-ui/client': 0.0.47 - '@modelcontextprotocol/sdk': 1.25.3(@cfworker/json-schema@4.1.1)(hono@4.11.7)(zod@3.25.76) - rxjs: 7.8.1 - transitivePeerDependencies: - - '@cfworker/json-schema' - - hono - - supports-color - - zod + '@ag-ui/core': 0.0.48 + '@bufbuild/protobuf': 2.11.0 + '@protobuf-ts/protoc': 2.11.1 - '@ag-ui/proto@0.0.47': + '@ag-ui/proto@0.0.52': dependencies: - '@ag-ui/core': 0.0.47 + '@ag-ui/core': 0.0.52 '@bufbuild/protobuf': 2.11.0 '@protobuf-ts/protoc': 2.11.1 + '@ai-sdk/anthropic@2.0.81(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 2.0.3 + '@ai-sdk/provider-utils': 3.0.25(zod@3.25.76) + zod: 3.25.76 + '@ai-sdk/anthropic@3.0.58(zod@3.25.76)': dependencies: '@ai-sdk/provider': 3.0.8 @@ -5267,6 +6059,24 @@ snapshots: '@vercel/oidc': 3.1.0 zod: 3.25.76 + '@ai-sdk/google-vertex@3.0.141(zod@3.25.76)': + dependencies: + '@ai-sdk/anthropic': 2.0.81(zod@3.25.76) + '@ai-sdk/google': 2.0.74(zod@3.25.76) + '@ai-sdk/openai-compatible': 1.0.39(zod@3.25.76) + '@ai-sdk/provider': 2.0.3 + '@ai-sdk/provider-utils': 3.0.25(zod@3.25.76) + google-auth-library: 10.7.0 + zod: 3.25.76 + transitivePeerDependencies: + - supports-color + + '@ai-sdk/google@2.0.74(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 2.0.3 + '@ai-sdk/provider-utils': 3.0.25(zod@3.25.76) + zod: 3.25.76 + '@ai-sdk/google@3.0.43(zod@3.25.76)': dependencies: '@ai-sdk/provider': 3.0.8 @@ -5280,12 +6090,25 @@ snapshots: pkce-challenge: 5.0.1 zod: 3.25.76 + '@ai-sdk/openai-compatible@1.0.39(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 2.0.3 + '@ai-sdk/provider-utils': 3.0.25(zod@3.25.76) + zod: 3.25.76 + '@ai-sdk/openai@3.0.41(zod@3.25.76)': dependencies: '@ai-sdk/provider': 3.0.8 '@ai-sdk/provider-utils': 4.0.19(zod@3.25.76) zod: 3.25.76 + '@ai-sdk/provider-utils@3.0.25(zod@3.25.76)': + dependencies: + '@ai-sdk/provider': 2.0.3 + '@standard-schema/spec': 1.1.0 + eventsource-parser: 3.0.6 + zod: 3.25.76 + '@ai-sdk/provider-utils@4.0.19(zod@3.25.76)': dependencies: '@ai-sdk/provider': 3.0.8 @@ -5293,6 +6116,10 @@ snapshots: eventsource-parser: 3.0.6 zod: 3.25.76 + '@ai-sdk/provider@2.0.3': + dependencies: + json-schema: 0.4.0 + '@ai-sdk/provider@3.0.8': dependencies: json-schema: 0.4.0 @@ -5304,6 +6131,26 @@ snapshots: package-manager-detector: 1.6.0 tinyexec: 1.0.2 + '@asamuzakjp/css-color@5.1.11': + dependencies: + '@asamuzakjp/generational-cache': 1.0.1 + '@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-color-parser': 4.1.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@asamuzakjp/dom-selector@7.1.1': + dependencies: + '@asamuzakjp/generational-cache': 1.0.1 + '@asamuzakjp/nwsapi': 2.3.9 + bidi-js: 1.0.3 + css-tree: 3.2.1 + is-potential-custom-element-name: 1.0.1 + + '@asamuzakjp/generational-cache@1.0.1': {} + + '@asamuzakjp/nwsapi@2.3.9': {} + '@babel/code-frame@7.29.0': dependencies: '@babel/helper-validator-identifier': 7.28.5 @@ -5408,6 +6255,10 @@ snapshots: '@braintree/sanitize-url@7.1.2': {} + '@bramus/specificity@2.4.2': + dependencies: + css-tree: 3.2.1 + '@bufbuild/protobuf@2.11.0': {} '@cfworker/json-schema@4.1.1': {} @@ -5429,32 +6280,61 @@ snapshots: '@chevrotain/utils@11.0.3': {} - '@copilotkit/a2ui-renderer@1.54.0-next.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(signal-polyfill@0.2.2)': + '@copilotkit/a2ui-renderer@1.55.2-next.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@a2ui/lit': 0.8.1(signal-polyfill@0.2.2) + '@a2ui/web_core': 0.9.0 clsx: 2.1.1 - markdown-it: 14.1.1 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) zod: 3.25.76 + zod-to-json-schema: 3.25.1(zod@3.25.76) + + '@copilotkit/core@1.55.2-next.1(@ag-ui/core@0.0.52)(zod@3.25.76)': + dependencies: + '@ag-ui/client': 0.0.52 + '@copilotkit/shared': 1.55.2-next.1(@ag-ui/core@0.0.52) + phoenix: 1.8.5 + rxjs: 7.8.1 + zod-to-json-schema: 3.25.1(zod@3.25.76) transitivePeerDependencies: - - signal-polyfill + - '@ag-ui/core' + - encoding + - zod + + '@copilotkit/license-verifier@0.0.1-a1': {} - '@copilotkit/react-core@1.54.0-next.6(@ag-ui/core@0.0.47)(@types/mdast@4.0.4)(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(graphql@16.12.0)(micromark-util-types@2.0.2)(micromark@4.0.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(signal-polyfill@0.2.2)(zod@3.25.76)': + '@copilotkit/react-core@1.55.2-next.1(@types/mdast@4.0.4)(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(graphql@16.12.0)(micromark-util-types@2.0.2)(micromark@4.0.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(zod@3.25.76)': dependencies: - '@ag-ui/client': 0.0.47 - '@copilotkit/runtime-client-gql': 1.54.0-next.6(@ag-ui/core@0.0.47)(graphql@16.12.0)(react@19.2.4) - '@copilotkit/shared': 1.54.0-next.6(@ag-ui/core@0.0.47) - '@copilotkitnext/core': 1.54.0-next.6(zod@3.25.76) - '@copilotkitnext/react': 1.54.0-next.6(@types/mdast@4.0.4)(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(micromark-util-types@2.0.2)(micromark@4.0.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(signal-polyfill@0.2.2) + '@ag-ui/client': 0.0.52 + '@ag-ui/core': 0.0.52 + '@copilotkit/a2ui-renderer': 1.55.2-next.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@copilotkit/core': 1.55.2-next.1(@ag-ui/core@0.0.52)(zod@3.25.76) + '@copilotkit/runtime-client-gql': 1.55.2-next.1(@ag-ui/core@0.0.52)(graphql@16.12.0)(react@19.2.4) + '@copilotkit/shared': 1.55.2-next.1(@ag-ui/core@0.0.52) + '@copilotkit/web-inspector': 1.55.2-next.1(@ag-ui/core@0.0.52)(zod@3.25.76) + '@jetbrains/websandbox': 1.2.1 + '@lit-labs/react': 2.1.3(@types/react@19.2.10) + '@radix-ui/react-dropdown-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.4(@types/react@19.2.10)(react@19.2.4) + '@radix-ui/react-tooltip': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@scarf/scarf': 1.4.0 + '@tanstack/react-virtual': 3.13.18(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + class-variance-authority: 0.7.1 + clsx: 2.1.1 + katex: 0.16.28 + lucide-react: 0.525.0(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) react-markdown: 8.0.7(@types/react@19.2.10)(react@19.2.4) + rxjs: 7.8.1 + streamdown: 1.6.11(@types/mdast@4.0.4)(micromark-util-types@2.0.2)(micromark@4.0.2)(react@19.2.4) + tailwind-merge: 3.4.0 + tw-animate-css: 1.4.0 untruncate-json: 0.0.1 + use-stick-to-bottom: 1.1.2(react@19.2.4) zod: 3.25.76 + zod-to-json-schema: 3.25.1(zod@3.25.76) transitivePeerDependencies: - - '@ag-ui/core' - '@types/mdast' - '@types/react' - '@types/react-dom' @@ -5462,14 +6342,13 @@ snapshots: - graphql - micromark - micromark-util-types - - signal-polyfill - supports-color - '@copilotkit/react-ui@1.54.0-next.6(@ag-ui/core@0.0.47)(@types/mdast@4.0.4)(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(graphql@16.12.0)(micromark-util-types@2.0.2)(micromark@4.0.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(signal-polyfill@0.2.2)(zod@3.25.76)': + '@copilotkit/react-ui@1.55.2-next.1(@ag-ui/core@0.0.52)(@types/mdast@4.0.4)(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(graphql@16.12.0)(micromark-util-types@2.0.2)(micromark@4.0.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(zod@3.25.76)': dependencies: - '@copilotkit/react-core': 1.54.0-next.6(@ag-ui/core@0.0.47)(@types/mdast@4.0.4)(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(graphql@16.12.0)(micromark-util-types@2.0.2)(micromark@4.0.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(signal-polyfill@0.2.2)(zod@3.25.76) - '@copilotkit/runtime-client-gql': 1.54.0-next.6(@ag-ui/core@0.0.47)(graphql@16.12.0)(react@19.2.4) - '@copilotkit/shared': 1.54.0-next.6(@ag-ui/core@0.0.47) + '@copilotkit/react-core': 1.55.2-next.1(@types/mdast@4.0.4)(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(graphql@16.12.0)(micromark-util-types@2.0.2)(micromark@4.0.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(zod@3.25.76) + '@copilotkit/runtime-client-gql': 1.55.2-next.1(@ag-ui/core@0.0.52)(graphql@16.12.0)(react@19.2.4) + '@copilotkit/shared': 1.55.2-next.1(@ag-ui/core@0.0.52) '@headlessui/react': 2.2.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 react-markdown: 10.1.0(@types/react@19.2.10)(react@19.2.4) @@ -5487,13 +6366,12 @@ snapshots: - micromark - micromark-util-types - react-dom - - signal-polyfill - supports-color - zod - '@copilotkit/runtime-client-gql@1.54.0-next.6(@ag-ui/core@0.0.47)(graphql@16.12.0)(react@19.2.4)': + '@copilotkit/runtime-client-gql@1.55.2-next.1(@ag-ui/core@0.0.52)(graphql@16.12.0)(react@19.2.4)': dependencies: - '@copilotkit/shared': 1.54.0-next.6(@ag-ui/core@0.0.47) + '@copilotkit/shared': 1.55.2-next.1(@ag-ui/core@0.0.52) '@urql/core': 5.2.0(graphql@16.12.0) react: 19.2.4 untruncate-json: 0.0.1 @@ -5503,41 +6381,54 @@ snapshots: - encoding - graphql - '@copilotkit/runtime@1.54.0-next.6(@ag-ui/encoder@0.0.47)(@cfworker/json-schema@4.1.1)(@copilotkitnext/shared@1.54.0-next.6)(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(@langchain/langgraph-sdk@1.5.5(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@opentelemetry/api@1.9.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(ws@8.19.0)': + '@copilotkit/runtime@1.55.2-next.1(@cfworker/json-schema@4.1.1)(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(@langchain/langgraph-sdk@1.9.20(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@opentelemetry/api@1.9.0)(langchain@1.4.4(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(ws@8.19.0)(zod-to-json-schema@3.25.1(zod@3.25.76)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(zod-to-json-schema@3.25.1(zod@3.25.76))': dependencies: - '@ag-ui/client': 0.0.47 - '@ag-ui/core': 0.0.47 - '@ag-ui/langgraph': 0.0.24(@ag-ui/client@0.0.47)(@ag-ui/core@0.0.47)(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@ag-ui/a2ui-middleware': 0.0.4(@ag-ui/client@0.0.52)(rxjs@7.8.1) + '@ag-ui/client': 0.0.52 + '@ag-ui/core': 0.0.52 + '@ag-ui/encoder': 0.0.52 + '@ag-ui/langgraph': 0.0.27(@ag-ui/client@0.0.52)(@ag-ui/core@0.0.52)(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(ws@8.19.0)(zod-to-json-schema@3.25.1(zod@3.25.76)) + '@ag-ui/mcp-apps-middleware': 0.0.3(@ag-ui/client@0.0.52)(@cfworker/json-schema@4.1.1)(hono@4.11.7)(zod@3.25.76) '@ai-sdk/anthropic': 3.0.58(zod@3.25.76) + '@ai-sdk/google': 3.0.43(zod@3.25.76) + '@ai-sdk/google-vertex': 3.0.141(zod@3.25.76) + '@ai-sdk/mcp': 1.0.25(zod@3.25.76) '@ai-sdk/openai': 3.0.41(zod@3.25.76) - '@copilotkit/shared': 1.54.0-next.6(@ag-ui/core@0.0.47) - '@copilotkitnext/agent': 1.54.0-next.6(@cfworker/json-schema@4.1.1)(hono@4.11.7) - '@copilotkitnext/runtime': 1.54.0-next.6(@ag-ui/client@0.0.47)(@ag-ui/core@0.0.47)(@ag-ui/encoder@0.0.47)(@cfworker/json-schema@4.1.1)(@copilotkitnext/shared@1.54.0-next.6)(zod@3.25.76) + '@copilotkit/license-verifier': 0.0.1-a1 + '@copilotkit/shared': 1.55.2-next.1(@ag-ui/core@0.0.52) '@graphql-yoga/plugin-defer-stream': 3.18.0(graphql-yoga@5.18.0(graphql@16.12.0))(graphql@16.12.0) '@hono/node-server': 1.19.9(hono@4.11.7) '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)) + '@modelcontextprotocol/sdk': 1.25.3(@cfworker/json-schema@4.1.1)(hono@4.11.7)(zod@3.25.76) + '@remix-run/node-fetch-server': 0.13.3 '@scarf/scarf': 1.4.0 + '@segment/analytics-node': 2.3.0 ai: 6.0.116(zod@3.25.76) + clarinet: 0.12.6 class-transformer: 0.5.1 class-validator: 0.14.3 + cors: 2.8.6 + express: 4.22.1 graphql: 16.12.0 graphql-scalars: 1.25.0(graphql@16.12.0) graphql-yoga: 5.18.0(graphql@16.12.0) hono: 4.11.7 openai: 4.104.0(ws@8.19.0)(zod@3.25.76) partial-json: 0.1.7 + phoenix: 1.8.5 pino: 9.14.0 pino-pretty: 11.3.0 reflect-metadata: 0.2.2 rxjs: 7.8.1 type-graphql: 2.0.0-rc.1(class-validator@0.14.3)(graphql-scalars@1.25.0(graphql@16.12.0))(graphql@16.12.0) + uuid: 10.0.0 + ws: 8.19.0 zod: 3.25.76 optionalDependencies: - '@langchain/langgraph-sdk': 1.5.5(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@langchain/langgraph-sdk': 1.9.20(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + langchain: 1.4.4(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(ws@8.19.0)(zod-to-json-schema@3.25.1(zod@3.25.76)) transitivePeerDependencies: - - '@ag-ui/encoder' - '@cfworker/json-schema' - - '@copilotkitnext/shared' - '@opentelemetry/api' - '@opentelemetry/exporter-trace-otlp-proto' - '@opentelemetry/sdk-trace-base' @@ -5546,117 +6437,75 @@ snapshots: - react - react-dom - supports-color + - svelte - utf-8-validate - - ws + - vue + - zod-to-json-schema - '@copilotkit/shared@1.54.0-next.6(@ag-ui/core@0.0.47)': + '@copilotkit/shared@1.55.2-next.1(@ag-ui/core@0.0.52)': dependencies: - '@ag-ui/core': 0.0.47 + '@ag-ui/client': 0.0.52 + '@ag-ui/core': 0.0.52 + '@copilotkit/license-verifier': 0.0.1-a1 '@segment/analytics-node': 2.3.0 + '@standard-schema/spec': 1.1.0 chalk: 4.1.2 graphql: 16.12.0 - uuid: 10.0.0 + partial-json: 0.1.7 + uuid: 11.1.0 zod: 3.25.76 + zod-to-json-schema: 3.25.1(zod@3.25.76) transitivePeerDependencies: - encoding - '@copilotkitnext/agent@1.54.0-next.6(@cfworker/json-schema@4.1.1)(hono@4.11.7)': + '@copilotkit/web-inspector@1.55.2-next.1(@ag-ui/core@0.0.52)(zod@3.25.76)': dependencies: - '@ag-ui/client': 0.0.47 - '@ai-sdk/anthropic': 3.0.58(zod@3.25.76) - '@ai-sdk/google': 3.0.43(zod@3.25.76) - '@ai-sdk/mcp': 1.0.25(zod@3.25.76) - '@ai-sdk/openai': 3.0.41(zod@3.25.76) - '@copilotkitnext/shared': 1.54.0-next.6 - '@modelcontextprotocol/sdk': 1.25.3(@cfworker/json-schema@4.1.1)(hono@4.11.7)(zod@3.25.76) - ai: 6.0.116(zod@3.25.76) - rxjs: 7.8.1 - zod: 3.25.76 + '@ag-ui/client': 0.0.52 + '@copilotkit/core': 1.55.2-next.1(@ag-ui/core@0.0.52)(zod@3.25.76) + lit: 3.3.2 + lucide: 0.525.0 + marked: 12.0.2 transitivePeerDependencies: - - '@cfworker/json-schema' - - hono - - supports-color + - '@ag-ui/core' + - encoding + - zod - '@copilotkitnext/core@1.54.0-next.6(zod@3.25.76)': + '@copilotkitnext/shared@1.54.1-next.6': dependencies: - '@ag-ui/client': 0.0.47 - '@copilotkitnext/shared': 1.54.0-next.6 - phoenix: 1.8.5 - rxjs: 7.8.1 - zod-to-json-schema: 3.25.1(zod@3.25.76) - transitivePeerDependencies: - - zod + '@ag-ui/client': 0.0.48 + '@standard-schema/spec': 1.1.0 + partial-json: 0.1.7 + uuid: 11.1.0 - '@copilotkitnext/react@1.54.0-next.6(@types/mdast@4.0.4)(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(micromark-util-types@2.0.2)(micromark@4.0.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(signal-polyfill@0.2.2)': + '@csstools/color-helpers@6.0.2': {} + + '@csstools/css-calc@3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': dependencies: - '@ag-ui/client': 0.0.47 - '@ag-ui/core': 0.0.47 - '@copilotkit/a2ui-renderer': 1.54.0-next.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(signal-polyfill@0.2.2) - '@copilotkitnext/core': 1.54.0-next.6(zod@3.25.76) - '@copilotkitnext/shared': 1.54.0-next.6 - '@copilotkitnext/web-inspector': 1.54.0-next.6(zod@3.25.76) - '@lit-labs/react': 2.1.3(@types/react@19.2.10) - '@radix-ui/react-dropdown-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.4(@types/react@19.2.10)(react@19.2.4) - '@radix-ui/react-tooltip': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - class-variance-authority: 0.7.1 - clsx: 2.1.1 - katex: 0.16.28 - lucide-react: 0.525.0(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - streamdown: 1.6.11(@types/mdast@4.0.4)(micromark-util-types@2.0.2)(micromark@4.0.2)(react@19.2.4) - tailwind-merge: 3.4.0 - ts-deepmerge: 7.0.3 - tw-animate-css: 1.4.0 - use-stick-to-bottom: 1.1.2(react@19.2.4) - zod: 3.25.76 - transitivePeerDependencies: - - '@types/mdast' - - '@types/react' - - '@types/react-dom' - - micromark - - micromark-util-types - - signal-polyfill - - supports-color + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 - '@copilotkitnext/runtime@1.54.0-next.6(@ag-ui/client@0.0.47)(@ag-ui/core@0.0.47)(@ag-ui/encoder@0.0.47)(@cfworker/json-schema@4.1.1)(@copilotkitnext/shared@1.54.0-next.6)(zod@3.25.76)': + '@csstools/css-color-parser@4.1.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': dependencies: - '@ag-ui/a2ui-middleware': 0.0.2(@ag-ui/client@0.0.47)(rxjs@7.8.1) - '@ag-ui/client': 0.0.47 - '@ag-ui/core': 0.0.47 - '@ag-ui/encoder': 0.0.47 - '@ag-ui/mcp-apps-middleware': 0.0.2(@ag-ui/client@0.0.47)(@cfworker/json-schema@4.1.1)(hono@4.11.7)(rxjs@7.8.1)(zod@3.25.76) - '@copilotkitnext/shared': 1.54.0-next.6 - cors: 2.8.6 - express: 4.22.1 - hono: 4.11.7 - phoenix: 1.8.5 - rxjs: 7.8.1 - ws: 8.19.0 - transitivePeerDependencies: - - '@cfworker/json-schema' - - bufferutil - - supports-color - - utf-8-validate - - zod + '@csstools/color-helpers': 6.0.2 + '@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 - '@copilotkitnext/shared@1.54.0-next.6': + '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': dependencies: - '@ag-ui/client': 0.0.47 - '@standard-schema/spec': 1.1.0 - partial-json: 0.1.7 - uuid: 11.1.0 + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-syntax-patches-for-csstree@1.1.5(css-tree@3.2.1)': + optionalDependencies: + css-tree: 3.2.1 + + '@csstools/css-tokenizer@4.0.0': {} - '@copilotkitnext/web-inspector@1.54.0-next.6(zod@3.25.76)': + '@emnapi/core@1.10.0': dependencies: - '@ag-ui/client': 0.0.47 - '@copilotkitnext/core': 1.54.0-next.6(zod@3.25.76) - lit: 3.3.2 - lucide: 0.525.0 - marked: 12.0.2 - transitivePeerDependencies: - - zod + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true '@emnapi/core@1.8.1': dependencies: @@ -5664,6 +6513,11 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true + '@emnapi/runtime@1.8.1': dependencies: tslib: 2.8.1 @@ -5674,6 +6528,11 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + '@envelop/core@5.5.0': dependencies: '@envelop/instrumentation': 1.0.0 @@ -5815,6 +6674,8 @@ snapshots: '@eslint/core': 0.17.0 levn: 0.4.1 + '@exodus/bytes@1.15.1': {} + '@fastify/busboy@3.2.0': {} '@floating-ui/core@1.7.4': @@ -6037,6 +6898,8 @@ snapshots: '@img/sharp-win32-x64@0.34.5': optional: true + '@jetbrains/websandbox@1.2.1': {} + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -6076,6 +6939,11 @@ snapshots: - '@opentelemetry/sdk-trace-base' - openai + '@langchain/langgraph-checkpoint@1.0.4(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))': + dependencies: + '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)) + uuid: 14.0.0 + '@langchain/langgraph-sdk@0.1.10(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@types/json-schema': 7.0.15 @@ -6087,16 +6955,36 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@langchain/langgraph-sdk@1.5.5(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@langchain/langgraph-sdk@1.9.20(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: + '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)) + '@langchain/protocol': 0.0.16 + '@types/json-schema': 7.0.15 p-queue: 9.1.0 p-retry: 7.1.1 - uuid: 13.0.0 + uuid: 14.0.0 optionalDependencies: - '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - optional: true + + '@langchain/langgraph@1.3.7(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76)': + dependencies: + '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)) + '@langchain/langgraph-checkpoint': 1.0.4(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76))) + '@langchain/langgraph-sdk': 1.9.20(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@langchain/protocol': 0.0.16 + '@standard-schema/spec': 1.1.0 + uuid: 14.0.0 + zod: 3.25.76 + optionalDependencies: + zod-to-json-schema: 3.25.1(zod@3.25.76) + transitivePeerDependencies: + - react + - react-dom + - svelte + - vue + + '@langchain/protocol@0.0.16': {} '@lit-labs/react@2.1.3(@types/react@19.2.10)': dependencies: @@ -6104,17 +6992,8 @@ snapshots: transitivePeerDependencies: - '@types/react' - '@lit-labs/signals@0.1.3': - dependencies: - lit: 3.3.2 - signal-polyfill: 0.2.2 - '@lit-labs/ssr-dom-shim@1.5.1': {} - '@lit/context@1.1.6': - dependencies: - '@lit/reactive-element': 2.1.2 - '@lit/react@1.0.8(@types/react@19.2.10)': dependencies: '@types/react': 19.2.10 @@ -6164,6 +7043,13 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true + '@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.2 + optional: true + '@next/env@16.1.6': {} '@next/eslint-plugin-next@16.1.6': @@ -6210,8 +7096,12 @@ snapshots: '@opentelemetry/api@1.9.0': {} + '@oxc-project/types@0.133.0': {} + '@pinojs/redact@0.4.0': {} + '@preact/signals-core@1.14.2': {} + '@protobuf-ts/protoc@2.11.1': {} '@radix-ui/primitive@1.1.3': {} @@ -6551,7 +7441,60 @@ snapshots: react: 19.2.4 react-redux: 9.2.0(@types/react@19.2.10)(react@19.2.4)(redux@5.0.1) - '@repeaterjs/repeater@3.0.6': {} + '@remix-run/node-fetch-server@0.13.3': {} + + '@repeaterjs/repeater@3.0.6': {} + + '@rolldown/binding-android-arm64@1.0.3': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.3': + optional: true + + '@rolldown/binding-darwin-x64@1.0.3': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.3': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.3': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.3': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.3': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.3': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.3': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.3': + optional: true + + '@rolldown/pluginutils@1.0.1': {} '@rtsao/scc@1.1.0': {} @@ -6702,11 +7645,53 @@ snapshots: '@tanstack/virtual-core@3.13.18': {} + '@testing-library/dom@10.4.1': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/runtime': 7.28.6 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + picocolors: 1.1.1 + pretty-format: 27.5.1 + + '@testing-library/jest-dom@6.9.1': + dependencies: + '@adobe/css-tools': 4.5.0 + aria-query: 5.3.2 + css.escape: 1.5.1 + dom-accessibility-api: 0.6.3 + picocolors: 1.1.1 + redent: 3.0.0 + + '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 7.28.6 + '@testing-library/dom': 10.4.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.10 + '@types/react-dom': 19.2.3(@types/react@19.2.10) + '@tybys/wasm-util@0.10.1': dependencies: tslib: 2.8.1 optional: true + '@tybys/wasm-util@0.10.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/aria-query@5.0.4': {} + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + '@types/d3-array@3.2.2': {} '@types/d3-axis@3.0.6': @@ -6828,6 +7813,8 @@ snapshots: dependencies: '@types/ms': 2.1.0 + '@types/deep-eql@4.0.2': {} + '@types/estree-jsx@1.0.5': dependencies: '@types/estree': 1.0.8 @@ -6968,7 +7955,7 @@ snapshots: debug: 4.4.3 minimatch: 9.0.5 semver: 7.7.3 - tinyglobby: 0.2.15 + tinyglobby: 0.2.17 ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: @@ -7060,6 +8047,52 @@ snapshots: '@vercel/oidc@3.1.0': {} + '@vitejs/plugin-react@6.0.2(vite@8.0.16(@types/node@20.19.31)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0))': + dependencies: + '@rolldown/pluginutils': 1.0.1 + vite: 8.0.16(@types/node@20.19.31)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0) + + '@vitest/expect@4.1.8': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.1.8 + '@vitest/utils': 4.1.8 + chai: 6.2.2 + tinyrainbow: 3.1.0 + + '@vitest/mocker@4.1.8(vite@8.0.16(@types/node@20.19.31)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0))': + dependencies: + '@vitest/spy': 4.1.8 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 8.0.16(@types/node@20.19.31)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0) + + '@vitest/pretty-format@4.1.8': + dependencies: + tinyrainbow: 3.1.0 + + '@vitest/runner@4.1.8': + dependencies: + '@vitest/utils': 4.1.8 + pathe: 2.0.3 + + '@vitest/snapshot@4.1.8': + dependencies: + '@vitest/pretty-format': 4.1.8 + '@vitest/utils': 4.1.8 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@4.1.8': {} + + '@vitest/utils@4.1.8': + dependencies: + '@vitest/pretty-format': 4.1.8 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 + '@whatwg-node/disposablestack@0.0.6': dependencies: '@whatwg-node/promise-helpers': 1.3.2 @@ -7113,6 +8146,8 @@ snapshots: acorn@8.15.0: {} + agent-base@7.1.4: {} + agentkeepalive@4.6.0: dependencies: humanize-ms: 1.2.1 @@ -7157,6 +8192,10 @@ snapshots: dependencies: tslib: 2.8.1 + aria-query@5.3.0: + dependencies: + dequal: 2.0.3 + aria-query@5.3.2: {} array-buffer-byte-length@1.0.2: @@ -7228,6 +8267,8 @@ snapshots: get-intrinsic: 1.3.0 is-array-buffer: 3.0.5 + assertion-error@2.0.1: {} + ast-types-flow@0.0.8: {} async-function@1.0.0: {} @@ -7252,6 +8293,12 @@ snapshots: baseline-browser-mapping@2.9.19: {} + bidi-js@1.0.3: + dependencies: + require-from-string: 2.0.2 + + bignumber.js@9.3.1: {} + body-parser@1.20.4: dependencies: bytes: 3.1.2 @@ -7304,6 +8351,8 @@ snapshots: node-releases: 2.0.27 update-browserslist-db: 1.2.3(browserslist@4.28.1) + buffer-equal-constant-time@1.0.1: {} + buffer@6.0.3: dependencies: base64-js: 1.5.1 @@ -7336,6 +8385,8 @@ snapshots: ccount@2.0.1: {} + chai@6.2.2: {} + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -7369,6 +8420,8 @@ snapshots: '@chevrotain/utils': 11.0.3 lodash-es: 4.17.21 + clarinet@0.12.6: {} + class-transformer@0.5.1: {} class-validator@0.14.3: @@ -7475,6 +8528,13 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + css-tree@3.2.1: + dependencies: + mdn-data: 2.27.1 + source-map-js: 1.2.1 + + css.escape@1.5.1: {} + csstype@3.2.3: {} cytoscape-cose-bilkent@4.1.0(cytoscape@3.33.1): @@ -7663,6 +8723,15 @@ snapshots: damerau-levenshtein@1.0.8: {} + data-uri-to-buffer@4.0.1: {} + + data-urls@7.0.0: + dependencies: + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1 + transitivePeerDependencies: + - '@noble/hashes' + data-view-buffer@1.0.2: dependencies: call-bound: 1.0.4 @@ -7681,6 +8750,8 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.2 + date-fns@4.4.0: {} + dateformat@4.6.3: {} dayjs@1.11.19: {} @@ -7701,6 +8772,8 @@ snapshots: decimal.js-light@2.5.1: {} + decimal.js@10.6.0: {} + decode-named-character-reference@1.3.0: dependencies: character-entities: 2.0.2 @@ -7745,6 +8818,10 @@ snapshots: dependencies: esutils: 2.0.3 + dom-accessibility-api@0.5.16: {} + + dom-accessibility-api@0.6.3: {} + dompurify@3.3.1: optionalDependencies: '@types/trusted-types': 2.0.7 @@ -7757,6 +8834,10 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 + ecdsa-sig-formatter@1.0.11: + dependencies: + safe-buffer: 5.2.1 + ee-first@1.1.1: {} electron-to-chromium@1.5.286: {} @@ -7776,10 +8857,10 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.3.0 - entities@4.5.0: {} - entities@6.0.1: {} + entities@8.0.0: {} + es-abstract@1.24.1: dependencies: array-buffer-byte-length: 1.0.2 @@ -7860,6 +8941,8 @@ snapshots: iterator.prototype: 1.1.5 safe-array-concat: 1.1.3 + es-module-lexer@2.1.0: {} + es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 @@ -8123,6 +9206,10 @@ snapshots: estree-util-is-identifier-name@3.0.0: {} + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + esutils@2.0.3: {} etag@1.8.1: {} @@ -8141,6 +9228,8 @@ snapshots: dependencies: eventsource-parser: 3.0.6 + expect-type@1.3.0: {} + express-rate-limit@7.5.1(express@5.2.1): dependencies: express: 5.2.1 @@ -8246,9 +9335,14 @@ snapshots: dependencies: format: 0.2.2 - fdir@6.5.0(picomatch@4.0.3): + fdir@6.5.0(picomatch@4.0.4): optionalDependencies: - picomatch: 4.0.3 + picomatch: 4.0.4 + + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 file-entry-cache@8.0.0: dependencies: @@ -8314,6 +9408,10 @@ snapshots: node-domexception: 1.0.0 web-streams-polyfill: 4.0.0-beta.3 + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + forwarded@0.2.0: {} fresh@0.5.2: {} @@ -8336,6 +9434,22 @@ snapshots: functions-have-names@1.2.3: {} + gaxios@7.1.5: + dependencies: + extend: 3.0.2 + https-proxy-agent: 7.0.6 + node-fetch: 3.3.2 + transitivePeerDependencies: + - supports-color + + gcp-metadata@8.1.2: + dependencies: + gaxios: 7.1.5 + google-logging-utils: 1.1.3 + json-bigint: 1.0.0 + transitivePeerDependencies: + - supports-color + generator-function@2.0.1: {} gensync@1.0.0-beta.2: {} @@ -8391,6 +9505,19 @@ snapshots: define-properties: 1.2.1 gopd: 1.2.0 + google-auth-library@10.7.0: + dependencies: + base64-js: 1.5.1 + ecdsa-sig-formatter: 1.0.11 + gaxios: 7.1.5 + gcp-metadata: 8.1.2 + google-logging-utils: 1.1.3 + jws: 4.0.1 + transitivePeerDependencies: + - supports-color + + google-logging-utils@1.1.3: {} + gopd@1.2.0: {} graceful-fs@4.2.11: {} @@ -8601,6 +9728,12 @@ snapshots: hono@4.11.7: {} + html-encoding-sniffer@6.0.0: + dependencies: + '@exodus/bytes': 1.15.1 + transitivePeerDependencies: + - '@noble/hashes' + html-url-attributes@3.0.1: {} html-void-elements@3.0.0: {} @@ -8613,6 +9746,13 @@ snapshots: statuses: 2.0.2 toidentifier: 1.0.1 + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + humanize-ms@1.2.1: dependencies: ms: 2.1.3 @@ -8646,6 +9786,8 @@ snapshots: imurmurhash@0.1.4: {} + indent-string@4.0.0: {} + inherits@2.0.4: {} inline-style-parser@0.1.1: {} @@ -8756,8 +9898,7 @@ snapshots: is-negative-zero@2.0.3: {} - is-network-error@1.3.0: - optional: true + is-network-error@1.3.0: {} is-number-object@1.1.1: dependencies: @@ -8768,6 +9909,8 @@ snapshots: is-plain-obj@4.1.0: {} + is-potential-custom-element-name@1.0.1: {} + is-promise@4.0.0: {} is-regex@1.2.1: @@ -8840,8 +9983,38 @@ snapshots: dependencies: argparse: 2.0.1 + jsdom@29.1.1: + dependencies: + '@asamuzakjp/css-color': 5.1.11 + '@asamuzakjp/dom-selector': 7.1.1 + '@bramus/specificity': 2.4.2 + '@csstools/css-syntax-patches-for-csstree': 1.1.5(css-tree@3.2.1) + '@exodus/bytes': 1.15.1 + css-tree: 3.2.1 + data-urls: 7.0.0 + decimal.js: 10.6.0 + html-encoding-sniffer: 6.0.0 + is-potential-custom-element-name: 1.0.1 + lru-cache: 11.5.1 + parse5: 8.0.1 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 6.0.1 + undici: 7.27.2 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 8.0.1 + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1 + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - '@noble/hashes' + jsesc@3.1.0: {} + json-bigint@1.0.0: + dependencies: + bignumber.js: 9.3.1 + json-buffer@3.0.1: {} json-schema-traverse@0.4.1: {} @@ -8867,6 +10040,17 @@ snapshots: object.assign: 4.1.7 object.values: 1.2.1 + jwa@2.0.1: + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + + jws@4.0.1: + dependencies: + jwa: 2.0.1 + safe-buffer: 5.2.1 + katex@0.16.28: dependencies: commander: 8.3.0 @@ -8879,6 +10063,25 @@ snapshots: kleur@4.1.5: {} + langchain@1.4.4(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(ws@8.19.0)(zod-to-json-schema@3.25.1(zod@3.25.76)): + dependencies: + '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)) + '@langchain/langgraph': 1.3.7(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76)))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(zod-to-json-schema@3.25.1(zod@3.25.76))(zod@3.25.76) + '@langchain/langgraph-checkpoint': 1.0.4(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76))) + langsmith: 0.7.6(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76))(ws@8.19.0) + zod: 3.25.76 + transitivePeerDependencies: + - '@opentelemetry/api' + - '@opentelemetry/exporter-trace-otlp-proto' + - '@opentelemetry/sdk-trace-base' + - openai + - react + - react-dom + - svelte + - vue + - ws + - zod-to-json-schema + langium@3.3.1: dependencies: chevrotain: 11.0.3 @@ -8899,6 +10102,14 @@ snapshots: '@opentelemetry/api': 1.9.0 openai: 4.104.0(ws@8.19.0)(zod@3.25.76) + langsmith@0.7.6(@opentelemetry/api@1.9.0)(openai@4.104.0(ws@8.19.0)(zod@3.25.76))(ws@8.19.0): + dependencies: + p-queue: 6.6.2 + optionalDependencies: + '@opentelemetry/api': 1.9.0 + openai: 4.104.0(ws@8.19.0)(zod@3.25.76) + ws: 8.19.0 + language-subtag-registry@0.3.23: {} language-tags@1.0.9: @@ -8919,36 +10130,69 @@ snapshots: lightningcss-android-arm64@1.30.2: optional: true + lightningcss-android-arm64@1.32.0: + optional: true + lightningcss-darwin-arm64@1.30.2: optional: true + lightningcss-darwin-arm64@1.32.0: + optional: true + lightningcss-darwin-x64@1.30.2: optional: true + lightningcss-darwin-x64@1.32.0: + optional: true + lightningcss-freebsd-x64@1.30.2: optional: true + lightningcss-freebsd-x64@1.32.0: + optional: true + lightningcss-linux-arm-gnueabihf@1.30.2: optional: true + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + lightningcss-linux-arm64-gnu@1.30.2: optional: true + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + lightningcss-linux-arm64-musl@1.30.2: optional: true + lightningcss-linux-arm64-musl@1.32.0: + optional: true + lightningcss-linux-x64-gnu@1.30.2: optional: true + lightningcss-linux-x64-gnu@1.32.0: + optional: true + lightningcss-linux-x64-musl@1.30.2: optional: true + lightningcss-linux-x64-musl@1.32.0: + optional: true + lightningcss-win32-arm64-msvc@1.30.2: optional: true + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + lightningcss-win32-x64-msvc@1.30.2: optional: true + lightningcss-win32-x64-msvc@1.32.0: + optional: true + lightningcss@1.30.2: dependencies: detect-libc: 2.1.2 @@ -8965,9 +10209,21 @@ snapshots: lightningcss-win32-arm64-msvc: 1.30.2 lightningcss-win32-x64-msvc: 1.30.2 - linkify-it@5.0.0: + lightningcss@1.32.0: dependencies: - uc.micro: 2.1.0 + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 lit-element@4.2.2: dependencies: @@ -9010,6 +10266,8 @@ snapshots: lru-cache@10.4.3: {} + lru-cache@11.5.1: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -9024,19 +10282,12 @@ snapshots: lucide@0.525.0: {} + lz-string@1.5.0: {} + magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 - markdown-it@14.1.1: - dependencies: - argparse: 2.0.1 - entities: 4.5.0 - linkify-it: 5.0.0 - mdurl: 2.0.0 - punycode.js: 2.3.1 - uc.micro: 2.1.0 - markdown-table@3.0.4: {} marked@12.0.2: {} @@ -9248,7 +10499,7 @@ snapshots: dependencies: '@types/mdast': 4.0.4 - mdurl@2.0.0: {} + mdn-data@2.27.1: {} media-typer@0.3.0: {} @@ -9670,6 +10921,8 @@ snapshots: mime@1.6.0: {} + min-indent@1.0.1: {} + minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 @@ -9697,6 +10950,8 @@ snapshots: nanoid@3.3.11: {} + nanoid@3.3.12: {} + napi-postinstall@0.3.4: {} natural-compare@1.4.0: {} @@ -9736,6 +10991,12 @@ snapshots: dependencies: whatwg-url: 5.0.0 + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + node-releases@2.0.27: {} object-assign@4.1.1: {} @@ -9780,6 +11041,8 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 + obug@2.1.2: {} + on-exit-leak-free@2.1.2: {} on-finished@2.4.1: @@ -9847,7 +11110,6 @@ snapshots: dependencies: eventemitter3: 5.0.4 p-timeout: 7.0.1 - optional: true p-retry@4.6.2: dependencies: @@ -9857,14 +11119,12 @@ snapshots: p-retry@7.1.1: dependencies: is-network-error: 1.3.0 - optional: true p-timeout@3.2.0: dependencies: p-finally: 1.0.0 - p-timeout@7.0.1: - optional: true + p-timeout@7.0.1: {} package-manager-detector@1.6.0: {} @@ -9895,6 +11155,10 @@ snapshots: dependencies: entities: 6.0.1 + parse5@8.0.1: + dependencies: + entities: 8.0.0 + parseurl@1.3.3: {} partial-json@0.1.7: {} @@ -9919,7 +11183,7 @@ snapshots: picomatch@2.3.1: {} - picomatch@4.0.3: {} + picomatch@4.0.4: {} pino-abstract-transport@2.0.0: dependencies: @@ -9981,6 +11245,12 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + postcss@8.5.15: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + postcss@8.5.6: dependencies: nanoid: 3.3.11 @@ -9989,6 +11259,12 @@ snapshots: prelude-ls@1.2.1: {} + pretty-format@27.5.1: + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + prismjs@1.27.0: {} prismjs@1.30.0: {} @@ -10021,8 +11297,6 @@ snapshots: end-of-stream: 1.4.5 once: 1.4.0 - punycode.js@2.3.1: {} - punycode@2.3.1: {} qrcode.react@4.2.0(react@19.2.4): @@ -10072,6 +11346,8 @@ snapshots: react-is@16.13.1: {} + react-is@17.0.2: {} + react-is@18.3.1: {} react-markdown@10.1.0(@types/react@19.2.10)(react@19.2.4): @@ -10205,6 +11481,11 @@ snapshots: - '@types/react' - redux + redent@3.0.0: + dependencies: + indent-string: 4.0.0 + strip-indent: 3.0.0 + redux-thunk@3.1.0(redux@5.0.1): dependencies: redux: 5.0.1 @@ -10382,6 +11663,27 @@ snapshots: robust-predicates@3.0.2: {} + rolldown@1.0.3: + dependencies: + '@oxc-project/types': 0.133.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.3 + '@rolldown/binding-darwin-arm64': 1.0.3 + '@rolldown/binding-darwin-x64': 1.0.3 + '@rolldown/binding-freebsd-x64': 1.0.3 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.3 + '@rolldown/binding-linux-arm64-gnu': 1.0.3 + '@rolldown/binding-linux-arm64-musl': 1.0.3 + '@rolldown/binding-linux-ppc64-gnu': 1.0.3 + '@rolldown/binding-linux-s390x-gnu': 1.0.3 + '@rolldown/binding-linux-x64-gnu': 1.0.3 + '@rolldown/binding-linux-x64-musl': 1.0.3 + '@rolldown/binding-openharmony-arm64': 1.0.3 + '@rolldown/binding-wasm32-wasi': 1.0.3 + '@rolldown/binding-win32-arm64-msvc': 1.0.3 + '@rolldown/binding-win32-x64-msvc': 1.0.3 + roughjs@4.6.6: dependencies: hachure-fill: 0.5.2 @@ -10442,6 +11744,10 @@ snapshots: safer-buffer@2.1.2: {} + saxes@6.0.0: + dependencies: + xmlchars: 2.2.0 + scheduler@0.27.0: {} secure-json-parse@2.7.0: {} @@ -10605,11 +11911,7 @@ snapshots: side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 - signal-polyfill@0.2.2: {} - - signal-utils@0.21.1(signal-polyfill@0.2.2): - dependencies: - signal-polyfill: 0.2.2 + siginfo@2.0.0: {} simple-wcswidth@1.1.2: {} @@ -10627,8 +11929,12 @@ snapshots: stable-hash@0.0.5: {} + stackback@0.0.2: {} + statuses@2.0.2: {} + std-env@4.1.0: {} + stop-iteration-iterator@1.1.0: dependencies: es-errors: 1.3.0 @@ -10737,6 +12043,10 @@ snapshots: strip-bom@3.0.0: {} + strip-indent@3.0.0: + dependencies: + min-indent: 1.0.1 + strip-json-comments@3.1.1: {} style-to-js@1.1.21: @@ -10770,6 +12080,8 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} + symbol-tree@3.2.4: {} + tabbable@6.4.0: {} tailwind-merge@3.4.0: {} @@ -10784,12 +12096,27 @@ snapshots: tiny-invariant@1.3.3: {} + tinybench@2.9.0: {} + tinyexec@1.0.2: {} tinyglobby@0.2.15: dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + tinyrainbow@3.1.0: {} + + tldts-core@7.4.2: {} + + tldts@7.4.2: + dependencies: + tldts-core: 7.4.2 to-regex-range@5.0.1: dependencies: @@ -10799,8 +12126,16 @@ snapshots: toidentifier@1.0.1: {} + tough-cookie@6.0.1: + dependencies: + tldts: 7.4.2 + tr46@0.0.3: {} + tr46@6.0.0: + dependencies: + punycode: 2.3.1 + tree-kill@1.2.2: {} trim-lines@3.0.1: {} @@ -10813,8 +12148,6 @@ snapshots: ts-dedent@2.2.0: {} - ts-deepmerge@7.0.3: {} - tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29 @@ -10936,8 +12269,6 @@ snapshots: typescript@5.9.3: {} - uc.micro@2.1.0: {} - ufo@1.6.3: {} unbox-primitive@1.1.0: @@ -10951,6 +12282,8 @@ snapshots: undici-types@6.21.0: {} + undici@7.27.2: {} + unified@10.1.2: dependencies: '@types/unist': 2.0.11 @@ -11104,8 +12437,7 @@ snapshots: uuid@11.1.0: {} - uuid@13.0.0: - optional: true + uuid@14.0.0: {} uuid@9.0.1: {} @@ -11164,6 +12496,49 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 + vite@8.0.16(@types/node@20.19.31)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.15 + rolldown: 1.0.3 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 20.19.31 + esbuild: 0.27.3 + fsevents: 2.3.3 + jiti: 2.6.1 + tsx: 4.21.0 + + vitest@4.1.8(@opentelemetry/api@1.9.0)(@types/node@20.19.31)(jsdom@29.1.1)(vite@8.0.16(@types/node@20.19.31)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)): + dependencies: + '@vitest/expect': 4.1.8 + '@vitest/mocker': 4.1.8(vite@8.0.16(@types/node@20.19.31)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)) + '@vitest/pretty-format': 4.1.8 + '@vitest/runner': 4.1.8 + '@vitest/snapshot': 4.1.8 + '@vitest/spy': 4.1.8 + '@vitest/utils': 4.1.8 + es-module-lexer: 2.1.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.2 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 4.1.0 + tinybench: 2.9.0 + tinyexec: 1.0.2 + tinyglobby: 0.2.17 + tinyrainbow: 3.1.0 + vite: 8.0.16(@types/node@20.19.31)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@opentelemetry/api': 1.9.0 + '@types/node': 20.19.31 + jsdom: 29.1.1 + transitivePeerDependencies: + - msw + vscode-jsonrpc@8.2.0: {} vscode-languageserver-protocol@3.17.5: @@ -11181,12 +12556,30 @@ snapshots: vscode-uri@3.0.8: {} + w3c-xmlserializer@5.0.0: + dependencies: + xml-name-validator: 5.0.0 + web-namespaces@2.0.1: {} + web-streams-polyfill@3.3.3: {} + web-streams-polyfill@4.0.0-beta.3: {} webidl-conversions@3.0.1: {} + webidl-conversions@8.0.1: {} + + whatwg-mimetype@5.0.0: {} + + whatwg-url@16.0.1: + dependencies: + '@exodus/bytes': 1.15.1 + tr46: 6.0.0 + webidl-conversions: 8.0.1 + transitivePeerDependencies: + - '@noble/hashes' + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -11237,6 +12630,11 @@ snapshots: dependencies: isexe: 2.0.0 + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + wonka@6.3.5: {} word-wrap@1.2.5: {} @@ -11251,6 +12649,10 @@ snapshots: ws@8.19.0: {} + xml-name-validator@5.0.0: {} + + xmlchars@2.2.0: {} + xtend@4.0.2: {} y18n@5.0.8: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 2ea70e5..1d729f4 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,4 @@ packages: - "apps/app" - "apps/mcp" + - "packages/*" diff --git a/turbo.json b/turbo.json index 4472312..bedb847 100644 --- a/turbo.json +++ b/turbo.json @@ -10,6 +10,9 @@ "outputs": [".next/**", "!.next/cache/**", "dist/**"] }, "lint": {}, + "test": { + "cache": false + }, "clean": { "cache": false } From 5ad492f75a1dff92590365b8531f7ead35e672a9 Mon Sep 17 00:00:00 2001 From: GeneralJerel <85066839+GeneralJerel@users.noreply.github.com> Date: Wed, 10 Jun 2026 08:52:30 -0700 Subject: [PATCH 02/10] Phase A2: migrate demo onto canonical generateSandboxedUi rails - CopilotRuntime now sets openGenerativeUI: true (auto-applies OpenGenerativeUIMiddleware; options extracted to a tested builder) - Demo-owned activity renderer for "open-generative-ui" events overrides the built-in via renderActivityMessages: keeps CSS-first gating + adds design system & importmap injection, idiomorph preview morphing, and continuous ResizeObserver autosize (demo non-regressions) - Zod-validated sandboxFunctions: sendPrompt (chat bridge via CustomEvent + OpenGenUIPromptBridge) and openLink (https-only + optional origin allowlist) - OPEN_GEN_UI_DESIGN_SKILL replaces the default shadcn designSkill - Python agent prompt contract switched widgetRenderer -> generateSandboxedUi (ordered params, css-first, Websandbox.connection.remote bridge, dynamic imports), protocol & quality bar preserved; prompt hoisted to src/prompt.py - 60 app tests + 15 design-system tests + 8 pytest, all red-green Co-Authored-By: Claude Fable 5 --- apps/agent/main.py | 57 +-- apps/agent/src/plan.py | 4 +- apps/agent/src/prompt.py | 77 +++ apps/agent/src/templates.py | 2 +- apps/agent/tests/test_canonical_contract.py | 68 +++ apps/app/package.json | 1 + apps/app/src/app/api/copilotkit/route.ts | 31 +- apps/app/src/app/layout.tsx | 18 +- .../open-generative-ui-renderer.test.tsx | 450 ++++++++++++++++++ .../open-generative-ui/frame-content.ts | 104 ++++ .../open-generative-ui/index.tsx | 20 + .../process-partial-html.ts | 38 ++ .../open-generative-ui/renderer.tsx | 428 +++++++++++++++++ .../open-generative-ui/schema.ts | 21 + .../open-generative-ui/websandbox-loader.ts | 29 ++ .../open-generative-ui/websandbox.d.ts | 5 + .../copilotkit-runtime-options.test.ts | 48 ++ .../app/src/lib/copilotkit-runtime-options.ts | 33 ++ .../sandbox/__tests__/prompt-bridge.test.tsx | 76 +++ .../__tests__/sandbox-functions.test.ts | 179 +++++++ apps/app/src/lib/sandbox/prompt-bridge.tsx | 30 ++ apps/app/src/lib/sandbox/sandbox-functions.ts | 84 ++++ .../src/__tests__/design-skill.test.ts | 25 + packages/design-system/src/index.ts | 23 + pnpm-lock.yaml | 3 + 25 files changed, 1769 insertions(+), 85 deletions(-) create mode 100644 apps/agent/src/prompt.py create mode 100644 apps/agent/tests/test_canonical_contract.py create mode 100644 apps/app/src/components/generative-ui/open-generative-ui/__tests__/open-generative-ui-renderer.test.tsx create mode 100644 apps/app/src/components/generative-ui/open-generative-ui/frame-content.ts create mode 100644 apps/app/src/components/generative-ui/open-generative-ui/index.tsx create mode 100644 apps/app/src/components/generative-ui/open-generative-ui/process-partial-html.ts create mode 100644 apps/app/src/components/generative-ui/open-generative-ui/renderer.tsx create mode 100644 apps/app/src/components/generative-ui/open-generative-ui/schema.ts create mode 100644 apps/app/src/components/generative-ui/open-generative-ui/websandbox-loader.ts create mode 100644 apps/app/src/components/generative-ui/open-generative-ui/websandbox.d.ts create mode 100644 apps/app/src/lib/__tests__/copilotkit-runtime-options.test.ts create mode 100644 apps/app/src/lib/copilotkit-runtime-options.ts create mode 100644 apps/app/src/lib/sandbox/__tests__/prompt-bridge.test.tsx create mode 100644 apps/app/src/lib/sandbox/__tests__/sandbox-functions.test.ts create mode 100644 apps/app/src/lib/sandbox/prompt-bridge.tsx create mode 100644 apps/app/src/lib/sandbox/sandbox-functions.ts create mode 100644 packages/design-system/src/__tests__/design-skill.test.ts diff --git a/apps/agent/main.py b/apps/agent/main.py index 4283880..0ecf17a 100644 --- a/apps/agent/main.py +++ b/apps/agent/main.py @@ -19,6 +19,7 @@ from src.todos import AgentState, todo_tools from src.form import generate_form from src.plan import plan_visualization +from src.prompt import SYSTEM_PROMPT load_dotenv() @@ -29,61 +30,7 @@ context_schema=AgentState, skills=[str(Path(__file__).parent / "skills")], checkpointer=BoundedMemorySaver(max_threads=200), - system_prompt=""" - You are a helpful assistant that helps users understand CopilotKit and LangGraph used together. - - Be brief in your explanations of CopilotKit and LangGraph, 1 to 2 sentences. - - When demonstrating charts, always call the query_data tool to fetch all data from the database first. - - ## Visual Response Skills - - You have the ability to produce rich, interactive visual responses using the - `widgetRenderer` component. When a user asks you to visualize, explain visually, - diagram, or illustrate something, you MUST use the `widgetRenderer` component - instead of plain text. - - The `widgetRenderer` component accepts three parameters: - - title: A short title for the visualization - - description: A one-sentence description of what the visualization shows - - html: A self-contained HTML fragment with inline `; +const OVERFLOW_HIDDEN_STYLE_TAG = + ""; + +export function ensureHead(html: string): string { + if (/]/i.test(html)) return html; + return `${html}`; +} + +/** + * Final sandbox document: importmap first (must precede any scripts so module + * resolution works), then design-system styles, then the generated css, then + * the generated html. Head content is injected right after the opening + * tag so it precedes anything the generated document put in its own head. + */ +export function buildFinalFrameContent(html: string, css?: string): string { + const headContent = + IMPORTMAP_SCRIPT_TAG + + DESIGN_SYSTEM_STYLE_TAG + + (css ? `` : ""); + const withHead = ensureHead(html); + const openTag = withHead.match(/]*>/i); + if (!openTag || openTag.index === undefined) { + return `${headContent}${withHead}`; + } + const insertAt = openTag.index + openTag[0].length; + return withHead.slice(0, insertAt) + headContent + withHead.slice(insertAt); +} + +/** + * Preview sandbox head: design-system styles, the generated css param, and any + * complete `); + if (previewStyles) parts.push(previewStyles); + return parts.join(""); +} + +/** + * Preview body update: morph via Idiomorph (preserves existing nodes, no + * flicker), falling back to a plain innerHTML assignment if Idiomorph is + * unavailable or throws. + */ +export function buildPreviewBodyMorph(body: string): string { + return `(function() { + var html = ${JSON.stringify(body)}; + if (typeof Idiomorph !== "undefined" && Idiomorph && Idiomorph.morph) { + try { + Idiomorph.morph(document.body, html, { morphStyle: 'innerHTML' }); + } catch (err) { + document.body.innerHTML = html; + } + } else { + document.body.innerHTML = html; + } +})();`; +} + +/** + * Continuous autosize, forked from the legacy widget-renderer bridge: a + * ResizeObserver on document.body plus a window resize listener report the + * content height to the parent on every change. Body height is forced to auto + * so the reading can shrink below the current iframe viewport. + */ +export const MEASUREMENT_JS = ` +(function() { + if (window.__oguiResizeInstalled) return; + window.__oguiResizeInstalled = true; + var style = document.createElement('style'); + style.textContent = 'html, body { overflow: hidden !important; height: auto !important; min-height: 0 !important; }'; + document.head.appendChild(style); + function reportHeight() { + var h = document.body.scrollHeight; + var cs = getComputedStyle(document.body); + h += parseFloat(cs.marginTop) || 0; + h += parseFloat(cs.marginBottom) || 0; + parent.postMessage({ type: '${RESIZE_MESSAGE_TYPE}', height: Math.ceil(h) }, '*'); + } + var ro = new ResizeObserver(reportHeight); + ro.observe(document.body); + window.addEventListener('resize', reportHeight); + window.addEventListener('load', reportHeight); + var interval = setInterval(reportHeight, 200); + setTimeout(function() { clearInterval(interval); }, 3000); + reportHeight(); +})(); +`; diff --git a/apps/app/src/components/generative-ui/open-generative-ui/index.tsx b/apps/app/src/components/generative-ui/open-generative-ui/index.tsx new file mode 100644 index 0000000..e6038c8 --- /dev/null +++ b/apps/app/src/components/generative-ui/open-generative-ui/index.tsx @@ -0,0 +1,20 @@ +import type { ReactActivityMessageRenderer } from "@copilotkit/react-core/v2"; +import { OpenGenUIActivityRenderer, LOADING_PHRASES } from "./renderer"; +import { + OPEN_GENERATIVE_UI_ACTIVITY_TYPE, + OpenGenUIContentSchema, + type OpenGenUIContent, +} from "./schema"; + +export { OpenGenUIActivityRenderer, LOADING_PHRASES }; +export { OPEN_GENERATIVE_UI_ACTIVITY_TYPE, OpenGenUIContentSchema }; +export type { OpenGenUIContent }; + +// Stable module-level renderer registration. Drop into CopilotKitProvider's +// renderActivityMessages to override the built-in open-generative-ui renderer +// (user-supplied renderers win the activityType lookup). +export const OPEN_GEN_UI_ACTIVITY_RENDERER = { + activityType: OPEN_GENERATIVE_UI_ACTIVITY_TYPE, + content: OpenGenUIContentSchema, + render: OpenGenUIActivityRenderer, +} satisfies ReactActivityMessageRenderer; diff --git a/apps/app/src/components/generative-ui/open-generative-ui/process-partial-html.ts b/apps/app/src/components/generative-ui/open-generative-ui/process-partial-html.ts new file mode 100644 index 0000000..3058ab9 --- /dev/null +++ b/apps/app/src/components/generative-ui/open-generative-ui/process-partial-html.ts @@ -0,0 +1,38 @@ +// Forked from @copilotkit/react-core/v2 src/v2/lib/processPartialHtml.ts + +/** + * Extracts all complete ` + + )} + + ); + }, + (prev, next) => prev.content === next.content +); diff --git a/apps/app/src/components/generative-ui/open-generative-ui/schema.ts b/apps/app/src/components/generative-ui/open-generative-ui/schema.ts new file mode 100644 index 0000000..b406701 --- /dev/null +++ b/apps/app/src/components/generative-ui/open-generative-ui/schema.ts @@ -0,0 +1,21 @@ +import { z } from "zod"; + +export const OPEN_GENERATIVE_UI_ACTIVITY_TYPE = "open-generative-ui"; + +// Activity content emitted by the runtime's OpenGenerativeUIMiddleware. +// Defined locally — @copilotkit/react-core/v2 does not export its +// OpenGenerativeUIContentSchema. +export const OpenGenUIContentSchema = z.object({ + initialHeight: z.number().optional(), + generating: z.boolean().optional(), + css: z.string().optional(), + cssComplete: z.boolean().optional(), + html: z.array(z.string()).optional(), + htmlComplete: z.boolean().optional(), + jsFunctions: z.string().optional(), + jsFunctionsComplete: z.boolean().optional(), + jsExpressions: z.array(z.string()).optional(), + jsExpressionsComplete: z.boolean().optional(), +}); + +export type OpenGenUIContent = z.infer; diff --git a/apps/app/src/components/generative-ui/open-generative-ui/websandbox-loader.ts b/apps/app/src/components/generative-ui/open-generative-ui/websandbox-loader.ts new file mode 100644 index 0000000..7986402 --- /dev/null +++ b/apps/app/src/components/generative-ui/open-generative-ui/websandbox-loader.ts @@ -0,0 +1,29 @@ +export interface SandboxInstance { + iframe: HTMLIFrameElement; + promise: Promise; + run: (code: string) => Promise; + destroy: () => void; +} + +export interface WebsandboxModule { + create: ( + localApi: Record unknown>, + options: { + frameContainer: HTMLElement; + frameContent: string; + allowAdditionalAttributes: string; + } + ) => SandboxInstance; +} + +type WebsandboxNamespace = { + default?: WebsandboxModule & { default?: WebsandboxModule }; +}; + +// websandbox ships a UMD bundle with its own webpack `default` export. +// Consumer bundlers wrap CJS under another `.default`, resulting in +// mod.default.default for the actual Websandbox class. +export async function loadWebsandbox(): Promise { + const mod = (await import("@jetbrains/websandbox")) as WebsandboxNamespace; + return (mod.default?.default ?? mod.default) as WebsandboxModule; +} diff --git a/apps/app/src/components/generative-ui/open-generative-ui/websandbox.d.ts b/apps/app/src/components/generative-ui/open-generative-ui/websandbox.d.ts new file mode 100644 index 0000000..682ccb8 --- /dev/null +++ b/apps/app/src/components/generative-ui/open-generative-ui/websandbox.d.ts @@ -0,0 +1,5 @@ +// @jetbrains/websandbox is a transitive dependency of @copilotkit/react-core +// (pnpm strict isolation — no hoisted types). Shorthand declaration so the +// dynamic import in websandbox-loader.ts typechecks; the loader narrows the +// module shape itself. +declare module "@jetbrains/websandbox"; diff --git a/apps/app/src/lib/__tests__/copilotkit-runtime-options.test.ts b/apps/app/src/lib/__tests__/copilotkit-runtime-options.test.ts new file mode 100644 index 0000000..4f05219 --- /dev/null +++ b/apps/app/src/lib/__tests__/copilotkit-runtime-options.test.ts @@ -0,0 +1,48 @@ +import { describe, it, expect } from "vitest"; +import { LangGraphHttpAgent } from "@copilotkit/runtime/langgraph"; +import { buildRuntimeOptions } from "../copilotkit-runtime-options"; + +describe("buildRuntimeOptions", () => { + it("enables openGenerativeUI", () => { + expect(buildRuntimeOptions({}).openGenerativeUI).toBe(true); + }); + + it("defines a default LangGraph agent", () => { + const options = buildRuntimeOptions({}); + expect(options.agents.default).toBeInstanceOf(LangGraphHttpAgent); + }); + + it("defaults the agent url to http://localhost:8123", () => { + const options = buildRuntimeOptions({}); + expect(options.agents.default.url).toBe("http://localhost:8123"); + }); + + it("prefixes bare host:port urls with http://", () => { + const options = buildRuntimeOptions({ langgraphUrl: "agent-host:8123" }); + expect(options.agents.default.url).toBe("http://agent-host:8123"); + }); + + it("preserves full urls as-is", () => { + const options = buildRuntimeOptions({ langgraphUrl: "https://agent.example.com" }); + expect(options.agents.default.url).toBe("https://agent.example.com"); + }); + + it("preserves the a2ui config", () => { + expect(buildRuntimeOptions({}).a2ui).toEqual({ injectA2UITool: true }); + }); + + it("omits mcpApps when mcpServerUrl is unset", () => { + expect(buildRuntimeOptions({}).mcpApps).toBeUndefined(); + }); + + it("includes mcpApps when mcpServerUrl is set", () => { + const options = buildRuntimeOptions({ mcpServerUrl: "http://localhost:5001/mcp" }); + expect(options.mcpApps).toEqual({ + servers: [{ + type: "http", + url: "http://localhost:5001/mcp", + serverId: "example_mcp_app", + }], + }); + }); +}); diff --git a/apps/app/src/lib/copilotkit-runtime-options.ts b/apps/app/src/lib/copilotkit-runtime-options.ts new file mode 100644 index 0000000..6ccac9e --- /dev/null +++ b/apps/app/src/lib/copilotkit-runtime-options.ts @@ -0,0 +1,33 @@ +import { LangGraphHttpAgent } from "@copilotkit/runtime/langgraph"; + +export interface RuntimeOptionsEnv { + langgraphUrl?: string; + mcpServerUrl?: string; +} + +// Normalize Render's fromService hostport (bare host:port) into a full URL +function normalizeLanggraphUrl(raw?: string): string { + if (!raw) return "http://localhost:8123"; + return raw.startsWith("http") ? raw : `http://${raw}`; +} + +export function buildRuntimeOptions(env: RuntimeOptionsEnv) { + return { + agents: { + default: new LangGraphHttpAgent({ + url: normalizeLanggraphUrl(env.langgraphUrl), + }), + }, + a2ui: { injectA2UITool: true }, + openGenerativeUI: true as const, + ...(env.mcpServerUrl && { + mcpApps: { + servers: [{ + type: "http" as const, + url: env.mcpServerUrl, + serverId: "example_mcp_app", + }], + }, + }), + }; +} diff --git a/apps/app/src/lib/sandbox/__tests__/prompt-bridge.test.tsx b/apps/app/src/lib/sandbox/__tests__/prompt-bridge.test.tsx new file mode 100644 index 0000000..9abae04 --- /dev/null +++ b/apps/app/src/lib/sandbox/__tests__/prompt-bridge.test.tsx @@ -0,0 +1,76 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { render, cleanup } from "@testing-library/react"; +import "@testing-library/jest-dom/vitest"; +import { OpenGenUIPromptBridge } from "@/lib/sandbox/prompt-bridge"; +import { SEND_PROMPT_EVENT } from "@/lib/sandbox/sandbox-functions"; + +const addMessage = vi.fn(); +const runAgent = vi.fn(); +const fakeAgent = { addMessage }; +const fakeCopilotKit = { runAgent }; + +vi.mock("@copilotkit/react-core/v2", () => ({ + useAgent: () => ({ agent: fakeAgent }), + useCopilotKit: () => ({ copilotkit: fakeCopilotKit }), +})); + +const dispatchSendPrompt = (text: string) => { + window.dispatchEvent( + new CustomEvent(SEND_PROMPT_EVENT, { detail: { text } }) + ); +}; + +describe("OpenGenUIPromptBridge", () => { + beforeEach(() => { + addMessage.mockClear(); + runAgent.mockClear(); + }); + + afterEach(() => { + cleanup(); + }); + + it("renders nothing", () => { + const { container } = render(); + expect(container).toBeEmptyDOMElement(); + }); + + it("submits the prompt via addMessage and runAgent", () => { + render(); + dispatchSendPrompt("draw a chart"); + + expect(addMessage).toHaveBeenCalledTimes(1); + expect(addMessage).toHaveBeenCalledWith( + expect.objectContaining({ + id: expect.any(String), + content: "draw a chart", + role: "user", + }) + ); + expect(runAgent).toHaveBeenCalledTimes(1); + expect(runAgent).toHaveBeenCalledWith({ agent: fakeAgent }); + }); + + it("ignores events without a string text", () => { + render(); + window.dispatchEvent( + new CustomEvent(SEND_PROMPT_EVENT, { detail: { text: 42 } }) + ); + window.dispatchEvent(new CustomEvent(SEND_PROMPT_EVENT)); + + expect(addMessage).not.toHaveBeenCalled(); + expect(runAgent).not.toHaveBeenCalled(); + }); + + it("removes the listener on unmount", () => { + const { unmount } = render(); + dispatchSendPrompt("first"); + expect(addMessage).toHaveBeenCalledTimes(1); + expect(runAgent).toHaveBeenCalledTimes(1); + + unmount(); + dispatchSendPrompt("second"); + expect(addMessage).toHaveBeenCalledTimes(1); + expect(runAgent).toHaveBeenCalledTimes(1); + }); +}); diff --git a/apps/app/src/lib/sandbox/__tests__/sandbox-functions.test.ts b/apps/app/src/lib/sandbox/__tests__/sandbox-functions.test.ts new file mode 100644 index 0000000..0a63ebb --- /dev/null +++ b/apps/app/src/lib/sandbox/__tests__/sandbox-functions.test.ts @@ -0,0 +1,179 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { + sendPromptFunction, + openLinkFunction, + isAllowedLinkUrl, + SANDBOX_FUNCTIONS, + SEND_PROMPT_EVENT, +} from "@/lib/sandbox/sandbox-functions"; + +describe("sendPromptFunction", () => { + let received: string[]; + const listener = (e: Event) => { + received.push((e as CustomEvent<{ text: string }>).detail.text); + }; + + beforeEach(() => { + received = []; + window.addEventListener(SEND_PROMPT_EVENT, listener); + }); + + afterEach(() => { + window.removeEventListener(SEND_PROMPT_EVENT, listener); + }); + + it("has the sendPrompt name", () => { + expect(sendPromptFunction.name).toBe("sendPrompt"); + }); + + it("dispatches exactly one CustomEvent with the text for valid args", async () => { + await expect( + sendPromptFunction.handler({ text: "draw a chart" }) + ).resolves.toEqual({ ok: true }); + expect(received).toEqual(["draw a chart"]); + }); + + it.each([ + ["missing text", {}], + ["empty string", { text: "" }], + ["number", { text: 42 }], + ["over 4000 chars", { text: "a".repeat(4001) }], + ["extra junk only", { junk: "x" }], + ])("throws and dispatches nothing for %s", async (_label, args) => { + await expect(sendPromptFunction.handler(args)).rejects.toThrow(); + expect(received).toEqual([]); + }); + + it("accepts text at exactly 4000 chars", async () => { + await expect( + sendPromptFunction.handler({ text: "a".repeat(4000) }) + ).resolves.toEqual({ ok: true }); + expect(received).toHaveLength(1); + }); +}); + +describe("openLinkFunction", () => { + let openSpy: ReturnType; + + beforeEach(() => { + openSpy = vi.spyOn(window, "open").mockImplementation(() => null); + }); + + afterEach(() => { + openSpy.mockRestore(); + vi.unstubAllEnvs(); + }); + + it("has the openLink name", () => { + expect(openLinkFunction.name).toBe("openLink"); + }); + + it("opens an https URL in a new tab with noopener,noreferrer", async () => { + await expect( + openLinkFunction.handler({ url: "https://example.com/docs" }) + ).resolves.toEqual({ ok: true }); + expect(openSpy).toHaveBeenCalledTimes(1); + expect(openSpy).toHaveBeenCalledWith( + "https://example.com/docs", + "_blank", + "noopener,noreferrer" + ); + }); + + it.each([ + ["javascript:", { url: "javascript:alert(1)" }], + ["data:", { url: "data:text/html," }], + ["http:", { url: "http://example.com" }], + ["file:", { url: "file:///etc/passwd" }], + ["malformed", { url: "not a url" }], + ["missing url", {}], + ])("throws and never opens for %s", async (_label, args) => { + await expect(openLinkFunction.handler(args)).rejects.toThrow(); + expect(openSpy).not.toHaveBeenCalled(); + }); + + it("rejects https URLs outside the env allowlist", async () => { + vi.stubEnv("NEXT_PUBLIC_OPEN_LINK_ALLOWED_ORIGINS", "https://github.com"); + await expect( + openLinkFunction.handler({ url: "https://evil.com/x" }) + ).rejects.toThrow(); + expect(openSpy).not.toHaveBeenCalled(); + }); + + it("allows https URLs inside the env allowlist", async () => { + vi.stubEnv("NEXT_PUBLIC_OPEN_LINK_ALLOWED_ORIGINS", "https://github.com"); + await expect( + openLinkFunction.handler({ url: "https://github.com/CopilotKit" }) + ).resolves.toEqual({ ok: true }); + expect(openSpy).toHaveBeenCalledWith( + "https://github.com/CopilotKit", + "_blank", + "noopener,noreferrer" + ); + }); +}); + +describe("isAllowedLinkUrl", () => { + afterEach(() => { + vi.unstubAllEnvs(); + }); + + it.each([ + "https://example.com", + "https://example.com/path?query=1#hash", + ])("allows %s without an allowlist", (url) => { + expect(isAllowedLinkUrl(url)).toBe(true); + }); + + it.each([ + "javascript:alert(1)", + "data:text/html,", + "http://example.com", + "file:///etc/passwd", + "vbscript:msgbox(1)", + "ftp://example.com", + "not a url", + "", + ])("rejects %s", (url) => { + expect(isAllowedLinkUrl(url)).toBe(false); + }); + + it("allows an https URL whose origin is in the allowlist", () => { + expect(isAllowedLinkUrl("https://github.com/x", ["https://github.com"])).toBe( + true + ); + }); + + it("rejects an https URL whose origin is not in the allowlist", () => { + expect(isAllowedLinkUrl("https://evil.com", ["https://github.com"])).toBe( + false + ); + }); + + it("rejects origin-prefix lookalike hosts", () => { + expect( + isAllowedLinkUrl("https://github.com.evil.com/x", ["https://github.com"]) + ).toBe(false); + }); + + it("falls back to the env allowlist when no explicit list is given", () => { + vi.stubEnv( + "NEXT_PUBLIC_OPEN_LINK_ALLOWED_ORIGINS", + "https://github.com, https://copilotkit.ai" + ); + expect(isAllowedLinkUrl("https://github.com/x")).toBe(true); + expect(isAllowedLinkUrl("https://copilotkit.ai/blog")).toBe(true); + expect(isAllowedLinkUrl("https://evil.com")).toBe(false); + }); +}); + +describe("SANDBOX_FUNCTIONS", () => { + it("contains sendPrompt and openLink with a stable reference", async () => { + expect(SANDBOX_FUNCTIONS.map((f) => f.name)).toEqual([ + "sendPrompt", + "openLink", + ]); + const again = await import("@/lib/sandbox/sandbox-functions"); + expect(again.SANDBOX_FUNCTIONS).toBe(SANDBOX_FUNCTIONS); + }); +}); diff --git a/apps/app/src/lib/sandbox/prompt-bridge.tsx b/apps/app/src/lib/sandbox/prompt-bridge.tsx new file mode 100644 index 0000000..d3939e2 --- /dev/null +++ b/apps/app/src/lib/sandbox/prompt-bridge.tsx @@ -0,0 +1,30 @@ +"use client"; + +import { useEffect, useRef } from "react"; +import { useAgent, useCopilotKit } from "@copilotkit/react-core/v2"; +import { SEND_PROMPT_EVENT } from "./sandbox-functions"; + +export function OpenGenUIPromptBridge() { + const { agent } = useAgent(); + const { copilotkit } = useCopilotKit(); + + const agentRef = useRef(agent); + const copilotkitRef = useRef(copilotkit); + useEffect(() => { agentRef.current = agent; }, [agent]); + useEffect(() => { copilotkitRef.current = copilotkit; }, [copilotkit]); + + useEffect(() => { + const handler = (e: Event) => { + const text = (e as CustomEvent<{ text?: unknown }>).detail?.text; + if (typeof text !== "string" || !text) return; + const a = agentRef.current; + const ck = copilotkitRef.current; + a.addMessage({ id: crypto.randomUUID(), content: text, role: "user" }); + ck.runAgent({ agent: a }); + }; + window.addEventListener(SEND_PROMPT_EVENT, handler); + return () => window.removeEventListener(SEND_PROMPT_EVENT, handler); + }, []); + + return null; +} diff --git a/apps/app/src/lib/sandbox/sandbox-functions.ts b/apps/app/src/lib/sandbox/sandbox-functions.ts new file mode 100644 index 0000000..7f1ee15 --- /dev/null +++ b/apps/app/src/lib/sandbox/sandbox-functions.ts @@ -0,0 +1,84 @@ +import { z } from "zod"; +import type { SandboxFunction } from "@copilotkit/react-core/v2"; + +export const SEND_PROMPT_EVENT = "opengenui:send-prompt"; + +const formatIssues = (error: z.ZodError) => + error.issues + .map((issue) => `${issue.path.join(".") || "(root)"}: ${issue.message}`) + .join("; "); + +const sendPromptParameters = z.object({ + text: z.string().min(1).max(4000), +}); + +export const sendPromptFunction: SandboxFunction = { + name: "sendPrompt", + description: + "Sends a message to the chat as if the user typed it. Call as: await Websandbox.connection.remote.sendPrompt({ text }).", + parameters: sendPromptParameters, + handler: async (args) => { + const result = sendPromptParameters.safeParse(args); + if (!result.success) { + throw new Error(`sendPrompt: invalid arguments — ${formatIssues(result.error)}`); + } + window.dispatchEvent( + new CustomEvent(SEND_PROMPT_EVENT, { detail: { text: result.data.text } }) + ); + return { ok: true }; + }, +}; + +const openLinkParameters = z.object({ + url: z.string().url(), +}); + +const envAllowedOrigins = (): string[] | undefined => { + const raw = process.env.NEXT_PUBLIC_OPEN_LINK_ALLOWED_ORIGINS; + if (!raw) return undefined; + const origins = raw + .split(",") + .map((origin) => origin.trim()) + .filter(Boolean); + return origins.length > 0 ? origins : undefined; +}; + +export function isAllowedLinkUrl( + url: string, + allowedOrigins?: readonly string[] +): boolean { + let parsed: URL; + try { + parsed = new URL(url); + } catch { + return false; + } + if (parsed.protocol !== "https:") return false; + const origins = allowedOrigins ?? envAllowedOrigins(); + if (origins) return origins.includes(parsed.origin); + return true; +} + +export const openLinkFunction: SandboxFunction = { + name: "openLink", + description: + "Opens an https link in a new browser tab. Call as: await Websandbox.connection.remote.openLink({ url }).", + parameters: openLinkParameters, + handler: async (args) => { + const result = openLinkParameters.safeParse(args); + if (!result.success) { + throw new Error(`openLink: invalid arguments — ${formatIssues(result.error)}`); + } + const { url } = result.data; + if (!isAllowedLinkUrl(url)) { + throw new Error(`openLink: url not allowed — ${url}`); + } + window.open(url, "_blank", "noopener,noreferrer"); + return { ok: true }; + }, +}; + +export const SANDBOX_FUNCTIONS: readonly SandboxFunction[] = [ + sendPromptFunction, + openLinkFunction, +]; diff --git a/packages/design-system/src/__tests__/design-skill.test.ts b/packages/design-system/src/__tests__/design-skill.test.ts new file mode 100644 index 0000000..bd1811c --- /dev/null +++ b/packages/design-system/src/__tests__/design-skill.test.ts @@ -0,0 +1,25 @@ +import { describe, it, expect } from "vitest"; +import { OPEN_GEN_UI_DESIGN_SKILL } from "../index.js"; + +describe("OPEN_GEN_UI_DESIGN_SKILL", () => { + it("is a non-empty string", () => { + expect(typeof OPEN_GEN_UI_DESIGN_SKILL).toBe("string"); + expect(OPEN_GEN_UI_DESIGN_SKILL.length).toBeGreaterThan(0); + }); + + it("references the design-system color tokens", () => { + expect(OPEN_GEN_UI_DESIGN_SKILL).toContain("--color-background-primary"); + }); + + it("references the SVG color-ramp classes", () => { + expect(OPEN_GEN_UI_DESIGN_SKILL).toContain(".c-purple"); + }); + + it("explains automatic dark mode", () => { + expect(OPEN_GEN_UI_DESIGN_SKILL.toLowerCase()).toContain("dark mode"); + }); + + it("does not carry over the canonical shadcn guidance", () => { + expect(OPEN_GEN_UI_DESIGN_SKILL.toLowerCase()).not.toContain("shadcn"); + }); +}); diff --git a/packages/design-system/src/index.ts b/packages/design-system/src/index.ts index d0afd2d..ee6effa 100644 --- a/packages/design-system/src/index.ts +++ b/packages/design-system/src/index.ts @@ -429,6 +429,29 @@ a:hover { text-decoration: underline; } } `; +// ─── Open Generative UI Design Skill ───────────────────────────────── +// Injected as agent context for the generateSandboxedUi tool. Replaces the +// canonical default guidance, which contradicts this design system. +export const OPEN_GEN_UI_DESIGN_SKILL = ` +The sandbox already includes the OpenGenerativeUI design system. Build on it instead of restyling from scratch. + +Colors and theming: +- Use the CSS variables for every color: --color-background-primary / --color-background-secondary / --color-background-tertiary, --color-text-primary / --color-text-secondary / --color-text-tertiary, plus the semantic info/danger/success/warning variants (--color-background-info, --color-text-danger, --color-border-success, etc.). +- Dark mode is automatic via these variables — NEVER hardcode hex values for text or backgrounds. +- Fonts: --font-sans, --font-serif, --font-mono. Radii: --border-radius-md, --border-radius-lg, --border-radius-xl. + +Form controls: +- button, input (text/number/email/search/range/checkbox/radio), textarea, and select are pre-styled by the design system. Do not restyle these basics. + +SVG diagrams and charts: +- Pre-built color-ramp classes: .c-purple .c-teal .c-coral .c-pink .c-gray .c-blue .c-green .c-amber .c-red. +- Diagram helpers: .box .node .arr .leader for shapes/connectors, and .t .ts .th for text (body/small/heading). + +Layout: +- Use flex/grid with compact spacing. +- The css parameter should hold widget-specific styles only — the theme, form styles, and SVG classes are already loaded. +`.trim(); + // ─── CDN Import Map ────────────────────────────────────────────────── export const IMPORTMAP = { imports: { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 022a309..cf861f6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -38,6 +38,9 @@ importers: '@copilotkitnext/shared': specifier: 1.54.1-next.6 version: 1.54.1-next.6 + '@jetbrains/websandbox': + specifier: 1.2.1 + version: 1.2.1 '@repo/design-system': specifier: workspace:* version: link:../../packages/design-system From 4e705462db057fff4962412c01205f1288ec15ae Mon Sep 17 00:00:00 2001 From: GeneralJerel <85066839+GeneralJerel@users.noreply.github.com> Date: Wed, 10 Jun 2026 09:06:21 -0700 Subject: [PATCH 03/10] Phase A3+A4: retire legacy widgetRenderer rail; skills on procedural channel A3 (apps/app): - Delete widget-renderer.tsx and its useComponent registration; guard test pins zero widgetRenderer/widget-renderer references in src - Export overlay now rides the canonical activity content via assembleStandaloneHtmlFromActivity (importmap -> design system -> css -> Websandbox stub -> html -> jsFunctions/jsExpressions) - Legacy open-link postMessage handler hardened via isAllowedLinkUrl - template-card imports THEME_CSS from @repo/design-system A4 (apps/agent): - All three SKILL.md files rewritten to generateSandboxedUi ordered contract: css-first reveal, jsFunctions toolbox + jsExpressions stepwise invocations, parameterized generators for one-expression refinement turns, Websandbox bridge calls, dynamic-import library guidance; quality bar preserved - 17 new pytest contract tests (red-green); 25 total green Co-Authored-By: Claude Fable 5 --- .../skills/advanced-visualization/SKILL.md | 415 +++++++++++------ apps/agent/skills/master-playbook/SKILL.md | 283 +++++++----- apps/agent/skills/svg-diagrams/SKILL.md | 6 + apps/agent/tests/test_skills_contract.py | 69 +++ .../app/src/__tests__/no-legacy-rails.test.ts | 34 ++ apps/app/src/app/page.tsx | 7 +- .../__tests__/export-utils.test.ts | 83 ++++ .../generative-ui/export-overlay.tsx | 13 +- .../components/generative-ui/export-utils.ts | 62 ++- .../open-generative-ui-renderer.test.tsx | 46 +- .../open-generative-ui/frame-content.ts | 2 +- .../open-generative-ui/renderer.tsx | 30 +- .../generative-ui/widget-renderer.tsx | 419 ------------------ .../template-library/template-card.tsx | 2 +- .../use-generative-ui-examples.test.tsx | 80 ++++ .../src/hooks/use-generative-ui-examples.tsx | 14 - 16 files changed, 865 insertions(+), 700 deletions(-) create mode 100644 apps/agent/tests/test_skills_contract.py create mode 100644 apps/app/src/__tests__/no-legacy-rails.test.ts create mode 100644 apps/app/src/components/generative-ui/__tests__/export-utils.test.ts delete mode 100644 apps/app/src/components/generative-ui/widget-renderer.tsx create mode 100644 apps/app/src/hooks/__tests__/use-generative-ui-examples.test.tsx diff --git a/apps/agent/skills/advanced-visualization/SKILL.md b/apps/agent/skills/advanced-visualization/SKILL.md index 09a6e4e..320e5df 100644 --- a/apps/agent/skills/advanced-visualization/SKILL.md +++ b/apps/agent/skills/advanced-visualization/SKILL.md @@ -1,6 +1,6 @@ --- name: "Advanced Visualization Techniques" -description: "UI mockups, dashboards, advanced interactivity, generative art, simulations, math visualizations, and design system rules for producing rich HTML widget output." +description: "UI mockups, dashboards, advanced interactivity, generative art, simulations, math visualizations, and design system rules for producing rich generateSandboxedUi output." allowed-tools: [] --- @@ -12,6 +12,35 @@ simulations, math visualizations, and the design system that ties everything tog --- +## Part 0: The Tool Contract — generateSandboxedUi + +Everything in this volume ships through the `generateSandboxedUi` tool. The UI +streams as you generate it, so emit the parameters in this EXACT order: + +1. `initialHeight` — estimated height of the finished UI in px. +2. `placeholderMessages` — 2-4 short, playful progress messages. +3. `css` — ALL styles, up front. The user sees a placeholder until css is complete, + so keep it lean and put every style here for the css-first reveal. +4. `html` — clean body markup, streamed in live. No ` - +css parameter: +```css +.sim-controls { + display: flex; align-items: center; gap: 16px; + margin: 12px 0; font-size: 13px; + color: var(--color-text-secondary); +} +#sim { + width: 100%; height: 300px; + border-radius: var(--border-radius-md); + background: var(--color-background-secondary); +} +``` + +html parameter: +```html +
+``` - +function toggleSim() { + window.sim.running = !window.sim.running; + if (window.sim.running) stepSim(); +} + +function resetSim() { + const wasRunning = window.sim.running; + initSim(window.sim.particles.length); + if (!wasRunning) stepSim(); +} +``` + +jsExpressions parameter: +```js +initSim(50); +stepSim(); ``` ### Math Visualizations For plotting functions, showing geometric relationships, or exploring equations. **Pattern: Function Plotter with SVG** + +css parameter: +```css +.plot-controls { + display: flex; gap: 16px; align-items: center; + margin: 12px 0; font-size: 13px; + color: var(--color-text-secondary); +} +.plot-controls input[type="number"] { width: 60px; } +.plot-controls input[type="range"] { flex: 1; } +``` + +html parameter: ```html @@ -305,19 +386,20 @@ For plotting functions, showing geometric relationships, or exploring equations. -
+
+``` - ``` ### Sortable / Filterable Data Tables -```html - - +css parameter: +```css +.data-table { width: 100%; border-collapse: collapse; font-size: 14px; } +.data-table th { + text-align: left; padding: 8px 12px; font-weight: 500; + border-bottom: 0.5px solid var(--color-border-secondary); + color: var(--color-text-secondary); cursor: pointer; + user-select: none; font-size: 12px; +} +.data-table th:hover { color: var(--color-text-primary); } +.data-table td { + padding: 8px 12px; + border-bottom: 0.5px solid var(--color-border-tertiary); +} +.table-filter { width: 100%; margin-bottom: 12px; } +.status-pill { + font-size: 12px; padding: 2px 10px; + border-radius: var(--border-radius-md); +} +.status-pill.active { + background: var(--color-background-success); + color: var(--color-text-success); +} +.status-pill.paused { + background: var(--color-background-warning); + color: var(--color-text-warning); +} +``` + +html parameter: +```html + @@ -370,44 +470,51 @@ plotFn();
+``` - +jsExpressions parameter: +```js +initTable([ + ['Alpha', 42, 'Active'], + ['Beta', 18, 'Paused'], + ['Gamma', 91, 'Active'], +]); ``` --- @@ -456,7 +563,8 @@ plugins: { legend: { display: false } } ``` ### Dashboard Layout -Metric cards on top -> chart below -> sendPrompt for drill-down: +Metric cards on top -> chart below -> drill-down buttons wired to the +sendPrompt bridge (Part 6): ```html
- +
+
@@ -579,8 +694,10 @@ Instead, render all content stacked, then use post-stream JS to create tabs:
+``` - ``` -### sendPrompt() — Chat-Driven Interactivity -A global function that sends a message as if the user typed it. -Use it when the user's next action benefits from AI thinking: +### sendPrompt — Chat-Driven Interactivity +The host bridge exposes `await Websandbox.connection.remote.sendPrompt({ text })`, +which sends a message as if the user typed it. Use it when the user's next +action benefits from AI thinking. Wire it through a named jsFunction: +jsFunctions parameter: +```js +function drillDown(text) { + Websandbox.connection.remote.sendPrompt({ text }); +} +``` + +html parameter: ```html - - ``` **Use for**: drill-downs, follow-up questions, "explain this part". **Don't use for**: filtering, sorting, toggling — handle those in JS. -Append ` ↗` to button text when it triggers sendPrompt. +Append ` ↗` to button text when it triggers the bridge. +For external links use `await Websandbox.connection.remote.openLink({ url })` +(https only — anything else is rejected). ### Responsive Grid Pattern ```css @@ -653,22 +784,33 @@ Use `minmax(0, 1fr)` if children have large min-content that could overflow. --- -## Part 7: External Libraries (CDN Allowlist) +## Part 7: External Libraries -Only these CDN origins work (CSP-enforced): -- `cdnjs.cloudflare.com` -- `esm.sh` -- `cdn.jsdelivr.net` -- `unpkg.com` +### Importmap Libraries (Pre-Injected) -### Useful Libraries +An importmap for `three`, `gsap`, `d3`, and `chart.js` (served via esm.sh) is +pre-injected into every sandbox. PREFER loading them with dynamic imports inside +jsFunctions/jsExpressions: -**Chart.js** (data visualization): -```html - +```js +async function setupScene() { + const THREE = await import('three'); + const { OrbitControls } = + await import('three/examples/jsm/controls/OrbitControls.js'); + // ... build the scene with real geometry and PBR materials. + // NEVER fake 3D with CSS transforms or Canvas 2D projection. +} +``` + +```js +const { default: gsap } = await import('gsap'); +const d3 = await import('d3'); +const { default: Chart } = await import('chart.js/auto'); ``` -**Three.js** (3D graphics) — use ES module import (import map resolves bare specifiers): +Where a module script genuinely belongs in the html parameter, +` ``` -Alternative UMD (global `THREE` variable): -```html - -``` -**D3.js** (advanced data viz, force layouts, geographic maps): -```html - -``` +**Critical**: Regular ` +``` + +jsExpressions parameter: +```js +updateParam(50); ``` ### Template: Step-Through Explainer For cyclic or staged processes (event loops, biological cycles, pipelines). -```html - +css parameter: +```css +.step-nav { + display: flex; + align-items: center; + gap: 12px; + margin: 12px 0; + font-size: 13px; +} +.step-nav button { + padding: 6px 16px; + border: 1px solid var(--color-border-tertiary, #ddd); + border-radius: 8px; + background: var(--color-background-secondary, #f5f5f5); + color: var(--color-text-primary, #333); + cursor: pointer; + font-size: 13px; +} +.step-nav button:hover { + background: var(--color-background-tertiary, #eee); +} +.dot { width: 8px; height: 8px; border-radius: 50%; + background: var(--color-border-tertiary, #ccc); + transition: background 0.2s; } +.dot.active { background: var(--color-text-info, #185FA5); } +.step-content { min-height: 300px; } +#dots { display: flex; gap: 6px; } +#step-label { margin-left: auto; color: var(--color-text-secondary, #888); } +``` +html parameter: +```html
-
+
- Step 1 of 4 + Step 1 of 4
+``` - +function prevStep() { + window.current = (window.current - 1 + window.steps.length) % window.steps.length; + renderStep(); +} +``` + +jsExpressions parameter: +```js +initSteps([ + { title: "Step 1", svg: `...`, desc: "What happens first" }, + { title: "Step 2", svg: `...`, desc: "Then this" }, +]); ``` ### CSS Animation Patterns (for live diagrams) +These belong in the css parameter alongside the rest of your styles: + ```css /* Flowing particles along a path */ @keyframes flow { @@ -261,41 +327,55 @@ For simple charts, hand-draw in SVG. No library needed. ### Approach: Chart.js (For Complex/Interactive Charts) -When you need tooltips, responsive legends, animations: +When you need tooltips, responsive legends, animations. `chart.js` is in the +pre-injected importmap — load it with a dynamic import inside a jsFunction: +html parameter: ```html - - - + }); +} +``` + +jsExpressions parameter: +```js +renderRevenueChart(); ``` --- @@ -305,6 +385,9 @@ new Chart(document.getElementById('myChart'), { For relationship diagrams (ERDs, class diagrams, sequence diagrams) where precise layout math isn't worth doing by hand. +Mermaid is not in the importmap — load it by URL in a module script placed in +the html parameter (CDN script tags still work there): + ```html
";', + jsExpressions: ['document.title = "";'], + }, + "Escapes" + ); + expect(doc).not.toContain('const s = "";'); + expect(doc).toContain('const s = "<\\/script>";'); + expect(doc).not.toContain('document.title = "";'); + expect(doc).toContain('document.title = "<\\/script>";'); + }); + + it("tolerates empty and missing fields", () => { + const doc = assembleStandaloneHtmlFromActivity({}); + expect(doc.startsWith("")).toBe(true); + expect(doc).toContain('` + : ""; return ` ${escapeHtml(title)} - ${IMPORT_MAP} + ${IMPORTMAP_SCRIPT_TAG} + ${content.css ? `\n ` : ""} + -
- ${html} -
- + ${body} + ${moduleScript} `; } diff --git a/apps/app/src/components/generative-ui/open-generative-ui/__tests__/open-generative-ui-renderer.test.tsx b/apps/app/src/components/generative-ui/open-generative-ui/__tests__/open-generative-ui-renderer.test.tsx index 86b5b98..0f88bf4 100644 --- a/apps/app/src/components/generative-ui/open-generative-ui/__tests__/open-generative-ui-renderer.test.tsx +++ b/apps/app/src/components/generative-ui/open-generative-ui/__tests__/open-generative-ui-renderer.test.tsx @@ -330,7 +330,7 @@ describe("OpenGenUIActivityRenderer", () => { }); it("updates container height on every __ogui_resize message from the sandbox iframe", async () => { - const { container } = renderRenderer({ + renderRenderer({ initialHeight: 200, html: ["
Done
"], htmlComplete: true, @@ -339,7 +339,7 @@ describe("OpenGenUIActivityRenderer", () => { await flushImport(); await resolveSandboxReady(); - const div = container.firstElementChild as HTMLElement; + const div = mockIframe.parentElement as HTMLElement; expect(div.style.height).toBe("200px"); await act(async () => { @@ -437,6 +437,48 @@ describe("OpenGenUIActivityRenderer", () => { expect(mockDestroy).toHaveBeenCalledTimes(1); }); + it("wraps the final sandbox in an export overlay once content is complete", async () => { + const { container } = renderRenderer({ + css: "body{--marker:gen-css}", + cssComplete: true, + html: ['
Done
'], + htmlComplete: true, + generating: false, + jsFunctions: "function greet() { return 'hi'; }", + jsExpressions: ["greet();"], + }); + await flushImport(); + + expect(container.querySelector('button[title="Options"]')).not.toBeNull(); + expect(mockCreate).toHaveBeenCalledTimes(1); + }); + + it("shows no export overlay while generating", async () => { + const { container, rerender } = renderRenderer({ + css: "body{--marker:gen-css}", + cssComplete: true, + html: ["
Hello
"], + htmlComplete: false, + generating: true, + }); + await flushImport(); + + expect(container.querySelector('button[title="Options"]')).toBeNull(); + + rerender( + rendererElement({ + css: "body{--marker:gen-css}", + cssComplete: true, + html: ["
Hello
"], + htmlComplete: true, + generating: false, + }) + ); + await flushImport(); + + expect(container.querySelector('button[title="Options"]')).not.toBeNull(); + }); + it("exposes a registration object ready for renderActivityMessages", () => { expect(OPEN_GEN_UI_ACTIVITY_RENDERER.activityType).toBe("open-generative-ui"); expect(OPEN_GEN_UI_ACTIVITY_RENDERER.render).toBe(OpenGenUIActivityRenderer); diff --git a/apps/app/src/components/generative-ui/open-generative-ui/frame-content.ts b/apps/app/src/components/generative-ui/open-generative-ui/frame-content.ts index 29d7354..6c8a4f4 100644 --- a/apps/app/src/components/generative-ui/open-generative-ui/frame-content.ts +++ b/apps/app/src/components/generative-ui/open-generative-ui/frame-content.ts @@ -74,7 +74,7 @@ export function buildPreviewBodyMorph(body: string): string { } /** - * Continuous autosize, forked from the legacy widget-renderer bridge: a + * Continuous autosize, forked from the legacy widget renderer bridge: a * ResizeObserver on document.body plus a window resize listener report the * content height to the parent on every change. Body height is forced to auto * so the reading can shrink below the current iframe viewport. diff --git a/apps/app/src/components/generative-ui/open-generative-ui/renderer.tsx b/apps/app/src/components/generative-ui/open-generative-ui/renderer.tsx index b8116a1..3e944a9 100644 --- a/apps/app/src/components/generative-ui/open-generative-ui/renderer.tsx +++ b/apps/app/src/components/generative-ui/open-generative-ui/renderer.tsx @@ -2,6 +2,8 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { useSandboxFunctions } from "@copilotkit/react-core/v2"; +import { ExportOverlay } from "../export-overlay"; +import { assembleStandaloneHtmlFromActivity } from "../export-utils"; import { IDIOMORPH_JS } from "../idiomorph-inline"; import type { OpenGenUIContent } from "./schema"; import { @@ -369,7 +371,21 @@ const OpenGenUIActivityRendererInner = React.memo( const showLoading = isGenerating && !hasVisibleSandbox; const loadingPhrase = useLoadingPhrase(showLoading); - return ( + const isComplete = !isGenerating && !!content.htmlComplete; + const exportHtml = useMemo( + () => + isComplete + ? assembleStandaloneHtmlFromActivity({ + css: content.css, + html: content.html, + jsFunctions: content.jsFunctions, + jsExpressions: content.jsExpressions, + }) + : undefined, + [isComplete, content] + ); + + const frame = (
); + + if (!isComplete) return frame; + + return ( + + {frame} + + ); }, (prev, next) => prev.content === next.content ); diff --git a/apps/app/src/components/generative-ui/widget-renderer.tsx b/apps/app/src/components/generative-ui/widget-renderer.tsx deleted file mode 100644 index 56efe26..0000000 --- a/apps/app/src/components/generative-ui/widget-renderer.tsx +++ /dev/null @@ -1,419 +0,0 @@ -"use client"; - -import { useEffect, useRef, useState, useCallback } from "react"; -import { z } from "zod"; -import { - THEME_CSS, - SVG_CLASSES_CSS, - FORM_STYLES_WITH_STAGGER_CSS, - IMPORTMAP_SCRIPT_TAG, -} from "@repo/design-system"; -import { ExportOverlay } from "./export-overlay"; -import { IDIOMORPH_JS } from "./idiomorph-inline"; - -// ─── Zod Schema (CopilotKit parameter contract) ───────────────────── -export const WidgetRendererProps = z.object({ - title: z - .string() - .describe("Short title for the visualization, e.g. 'Binary Search' or 'Load Balancer Architecture'"), - description: z - .string() - .describe("One-sentence explanation of what this visualization demonstrates"), - html: z - .string() - .describe( - "Self-contained HTML fragment with inline - - -
- ${initialHtml} -
- - - -`; -} - -// ─── Loading Phrases ───────────────────────────────────────────────── -const LOADING_PHRASES = [ - "Sketching pixels", - "Wiring up nodes", - "Painting gradients", - "Compiling visuals", - "Arranging atoms", - "Rendering magic", - "Polishing edges", -]; - -function useLoadingPhrase(active: boolean) { - const [index, setIndex] = useState(0); - useEffect(() => { - if (!active) return; - const interval = setInterval(() => { - setIndex((i) => (i + 1) % LOADING_PHRASES.length); - }, 1800); - return () => clearInterval(interval); - }, [active]); - return LOADING_PHRASES[index]; -} - -// ─── React Component ───────────────────────────────────────────────── - -export function WidgetRenderer({ title, html }: WidgetRendererProps) { - const iframeRef = useRef(null); - const [height, setHeight] = useState(0); - const [loaded, setLoaded] = useState(false); - // Whether the iframe shell has been initialized - const shellReadyRef = useRef(false); - // Track the last html sent to the iframe to avoid redundant updates - const committedHtmlRef = useRef(""); - // Tracks whether html content has settled (stopped changing) - const [htmlSettled, setHtmlSettled] = useState(false); - const [prevHtml, setPrevHtml] = useState(html); - const settledTimerRef = useRef | null>(null); - const fadeTimerRef = useRef | null>(null); - const [fadingOut, setFadingOut] = useState(false); - - const handleMessage = useCallback((e: MessageEvent) => { - // Only handle messages from our own iframe - if ( - iframeRef.current && - e.source === iframeRef.current.contentWindow && - e.data?.type === "widget-resize" && - typeof e.data.height === "number" - ) { - setHeight(Math.max(50, Math.min(e.data.height, 4000))); - } - }, []); - - useEffect(() => { - window.addEventListener("message", handleMessage); - return () => window.removeEventListener("message", handleMessage); - }, [handleMessage]); - - // Reset settled/fade state when html changes (adjust state during render) - if (html !== prevHtml) { - setPrevHtml(html); - setHtmlSettled(false); - setFadingOut(false); - } - - // Initialize the iframe shell once when html first appears. - // Shell loads EMPTY so partial streaming fragments (e.g. unclosed in generated css - Legacy four-CDN CSP meta restored on the final sandbox frame - prompt.py + skills no longer teach top-level await in jsFunctions / jsExpressions (classic-script semantics; snippets wrapped in async fns) - Seed templates use the Websandbox bridge form; apply_template appends a canonical-translation usage note - Vestigial unvalidated open-link postMessage handler removed from page.tsx - turbo lint/test dependsOn ^build; CI now runs pnpm test + new pytest job - Dockerfile.app + render.yaml build @repo/design-system before the app - README + docs/generative-ui.md rewritten to the canonical rails - New coverage: process-partial-html (12), seed-templates, MCP renderer, resize clamping/non-finite guard, morph-enter entrance parity Suites: 97 app + 15 design-system + 4 mcp vitest, 32 pytest — all green. Co-Authored-By: Claude Fable 5 --- .github/workflows/ci.yml | 26 ++- README.md | 14 +- .../skills/advanced-visualization/SKILL.md | 20 ++- apps/agent/skills/master-playbook/SKILL.md | 7 +- apps/agent/src/prompt.py | 18 +- apps/agent/src/templates.py | 15 ++ apps/agent/tests/test_canonical_contract.py | 60 +++++-- apps/agent/tests/test_skills_contract.py | 40 ++++- .../app/src/__tests__/no-legacy-rails.test.ts | 6 +- apps/app/src/app/page.tsx | 20 +-- .../__tests__/export-utils.test.ts | 46 ++++- .../generative-ui/export-overlay.tsx | 5 +- .../components/generative-ui/export-utils.ts | 38 +++-- .../open-generative-ui-renderer.test.tsx | 159 +++++++++++++++++- .../__tests__/process-partial-html.test.ts | 90 ++++++++++ .../open-generative-ui/frame-content.ts | 53 +++++- .../open-generative-ui/renderer.tsx | 27 ++- .../__tests__/seed-templates.test.ts | 28 +++ .../template-library/seed-templates.ts | 4 +- .../__tests__/sandbox-functions.test.ts | 6 +- apps/mcp/tests/renderer.test.ts | 39 +++++ docker/Dockerfile.app | 10 +- docs/generative-ui.md | 40 +++-- render.yaml | 4 +- turbo.json | 5 +- 25 files changed, 666 insertions(+), 114 deletions(-) create mode 100644 apps/app/src/components/generative-ui/open-generative-ui/__tests__/process-partial-html.test.ts create mode 100644 apps/app/src/components/template-library/__tests__/seed-templates.test.ts create mode 100644 apps/mcp/tests/renderer.test.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 13573d7..9dc6787 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -130,10 +130,34 @@ jobs: - name: Run linting run: pnpm lint + - name: Run tests + run: pnpm test + + agent-tests: + name: Agent tests (pytest) + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false + + - name: Install uv + run: pip install uv + + - name: Sync agent dependencies + working-directory: apps/agent + run: uv sync + + - name: Run pytest + working-directory: apps/agent + run: uv run pytest -q + notify-slack: name: Notify Slack on Failure runs-on: ubuntu-latest - needs: [smoke, lint] + needs: [smoke, lint, agent-tests] if: | failure() && github.event_name == 'schedule' diff --git a/README.md b/README.md index 0d6aa78..eabf745 100644 --- a/README.md +++ b/README.md @@ -127,15 +127,17 @@ Deep agents also provide built-in planning (`write_todos`), filesystem tools, an 1. **User sends a prompt** via the CopilotKit chat UI 2. **Deep agent decides** whether to respond with text, call a tool, or render a visual component — consulting relevant skills as needed -3. **`widgetRenderer`** — a frontend `useComponent` hook — receives the agent's HTML and renders it in a sandboxed iframe -4. **Skeleton loading** shows while the iframe loads, then content fades in smoothly -5. **ResizeObserver** inside the iframe reports content height back to the parent for seamless auto-sizing +3. **`generateSandboxedUi`** — the canonical tool the CopilotKit runtime exposes when `openGenerativeUI` is enabled — receives the UI as ordered streaming parameters: `initialHeight` → `placeholderMessages` → `css` → `html` → `jsFunctions` → `jsExpressions` +4. **`OpenGenerativeUIMiddleware`** in the runtime translates the streaming tool call into `open-generative-ui` activity events the frontend subscribes to +5. **The demo's activity renderer** (registered via `renderActivityMessages`) shows the html streaming in live — morphing each update into a preview iframe with Idiomorph so nothing flickers — then boots the final websandbox iframe with the shared design-system CSS and CDN importmap injected +6. **Sandbox bridge + autosize** — the generated UI calls back into the host through Zod-validated `sendPrompt`/`openLink` sandbox functions, and a ResizeObserver inside the iframe continuously reports content height for seamless auto-sizing ### Key CopilotKit Patterns -| Pattern | Hook | Example | -|---------|------|---------| -| Generative UI | `useComponent` | Pie charts, bar charts, widget renderer | +| Pattern | Hook / Option | Example | +|---------|---------------|---------| +| Open Generative UI | `openGenerativeUI` + `renderActivityMessages` | Streaming sandboxed widgets via `generateSandboxedUi` | +| Generative UI | `useComponent` | Pie charts, bar charts | | Frontend tools | `useFrontendTool` | Theme toggle | | Human-in-the-loop | `useHumanInTheLoop` | Meeting scheduler | | Default tool render | `useDefaultRenderTool` | Tool execution status | diff --git a/apps/agent/skills/advanced-visualization/SKILL.md b/apps/agent/skills/advanced-visualization/SKILL.md index 320e5df..b1c9e78 100644 --- a/apps/agent/skills/advanced-visualization/SKILL.md +++ b/apps/agent/skills/advanced-visualization/SKILL.md @@ -789,8 +789,10 @@ Use `minmax(0, 1fr)` if children have large min-content that could overflow. ### Importmap Libraries (Pre-Injected) An importmap for `three`, `gsap`, `d3`, and `chart.js` (served via esm.sh) is -pre-injected into every sandbox. PREFER loading them with dynamic imports inside -jsFunctions/jsExpressions: +pre-injected into every sandbox. jsFunctions and jsExpressions execute as classic +scripts, where top-level await is a SyntaxError that fails silently — so PREFER +loading libraries with dynamic imports INSIDE an async function declared in +jsFunctions, and keep jsExpressions synchronous invocations of those functions: ```js async function setupScene() { @@ -803,9 +805,12 @@ async function setupScene() { ``` ```js -const { default: gsap } = await import('gsap'); -const d3 = await import('d3'); -const { default: Chart } = await import('chart.js/auto'); +async function setupLibraries() { + const { default: gsap } = await import('gsap'); + const d3 = await import('d3'); + const { default: Chart } = await import('chart.js/auto'); + // ... use the libraries here. +} ``` Where a module script genuinely belongs in the html parameter, @@ -820,8 +825,9 @@ import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'; ``` **Critical**: Regular `", + html: ["
"], + }, + "Css escape" + ); + expect(doc).not.toContain(""); + expect(doc).toContain("body{color:red}<\\/style>"); + }); + it("tolerates empty and missing fields", () => { const doc = assembleStandaloneHtmlFromActivity({}); expect(doc.startsWith("")).toBe(true); diff --git a/apps/app/src/components/generative-ui/export-overlay.tsx b/apps/app/src/components/generative-ui/export-overlay.tsx index 0efe72c..7cedaca 100644 --- a/apps/app/src/components/generative-ui/export-overlay.tsx +++ b/apps/app/src/components/generative-ui/export-overlay.tsx @@ -78,7 +78,8 @@ export function ExportOverlay({ ); }, [exportHtml]); - const showTrigger = ready && exportHtml && (hovered || menuOpen); + const exportable = ready && !!exportHtml; + const showTrigger = exportable && (hovered || menuOpen); return (
setHovered(true)} onMouseLeave={() => setHovered(false)} > + {exportable && (
+ )} {children}
diff --git a/apps/app/src/components/generative-ui/export-utils.ts b/apps/app/src/components/generative-ui/export-utils.ts index 8b92478..7b1d5ad 100644 --- a/apps/app/src/components/generative-ui/export-utils.ts +++ b/apps/app/src/components/generative-ui/export-utils.ts @@ -28,28 +28,42 @@ function escapeScriptClose(js: string): string { return js.replace(/<\/script/gi, "<\\/script"); } +function escapeStyleClose(css: string): string { + return css.replace(/<\/style/gi, "<\\/style"); +} + /** * Wrap an open-generative-ui activity payload in a standalone document that * works when opened in a browser: importmap first, then the same design-system * css composition the live renderer injects, then the generated css, a * Websandbox stub so exported bridge calls degrade gracefully, the joined html - * chunks, and finally the generated js inside an await-friendly module script. + * chunks, and finally the generated js in ONE classic (non-module) script: + * jsFunctions at top level — so function declarations become window globals, + * matching the live websandbox rail where inline onclick="fn()" handlers + * resolve them — followed by the jsExpressions inside an async IIFE so they + * can use `await` (dynamic import() still resolves via the importmap in + * classic scripts). */ export function assembleStandaloneHtmlFromActivity( content: StandaloneActivityContent, title = "generated-widget" ): string { const body = content.html?.join("") ?? ""; - const jsParts = [ - ...(content.jsFunctions ? [content.jsFunctions] : []), - ...(content.jsExpressions ?? []), + const expressions = content.jsExpressions ?? []; + const scriptParts = [ + ...(content.jsFunctions ? [escapeScriptClose(content.jsFunctions)] : []), + ...(expressions.length > 0 + ? [ + `(async () => { +${expressions.map(escapeScriptClose).join("\n")} +})();`, + ] + : []), ]; - const moduleScript = - jsParts.length > 0 - ? `` : ""; return ` @@ -63,12 +77,12 @@ ${jsParts.map(escapeScriptClose).join("\n")} ${THEME_CSS} ${SVG_CLASSES_CSS} ${FORM_STYLES_CSS} - ${content.css ? `\n ` : ""} + ${content.css ? `\n ` : ""} ${body} - ${moduleScript} + ${generatedScript} `; } diff --git a/apps/app/src/components/generative-ui/open-generative-ui/__tests__/open-generative-ui-renderer.test.tsx b/apps/app/src/components/generative-ui/open-generative-ui/__tests__/open-generative-ui-renderer.test.tsx index 0f88bf4..8fed986 100644 --- a/apps/app/src/components/generative-ui/open-generative-ui/__tests__/open-generative-ui-renderer.test.tsx +++ b/apps/app/src/components/generative-ui/open-generative-ui/__tests__/open-generative-ui-renderer.test.tsx @@ -13,6 +13,7 @@ import { LOADING_PHRASES, type OpenGenUIContent, } from "../index"; +import { THROTTLE_MS } from "../renderer"; // The react-core v2 dist entry imports index.css, which vitest's node loader // rejects (same precedent as src/lib/sandbox/__tests__/prompt-bridge.test.tsx) @@ -120,7 +121,9 @@ describe("OpenGenUIActivityRenderer", () => { const { container } = renderRenderer({ initialHeight: 300, generating: true }); await flushImport(); - const div = container.firstElementChild as HTMLElement; + // The root is the constant ExportOverlay wrapper; the frame div with the + // height style is its child. + const div = container.querySelector("div[style]")!; expect(div.style.height).toBe("300px"); expect(container.textContent).toContain(LOADING_PHRASES[0]); expect(mockCreate).not.toHaveBeenCalled(); @@ -144,7 +147,7 @@ describe("OpenGenUIActivityRenderer", () => { }) ); await act(async () => { - await new Promise((r) => setTimeout(r, 1100)); + await new Promise((r) => setTimeout(r, THROTTLE_MS + 100)); }); await flushImport(); @@ -197,8 +200,14 @@ describe("OpenGenUIActivityRenderer", () => { const morphCode = morphCalls[morphCalls.length - 1]![0] as string; expect(morphCode).toContain("Idiomorph.morph(document.body"); expect(morphCode).toContain("morphStyle: 'innerHTML'"); + // Streaming entrance animation: new nodes are tagged morph-enter so the + // design system's fadeSlideIn rule animates them in (legacy bridge parity). + expect(morphCode).toContain("beforeNodeAdded"); + expect(morphCode).toContain("morph-enter"); expect(morphCode).toContain("document.body.innerHTML"); expect(morphCode).toContain("Hello"); + // processPartialHtml must have stripped the wrapper before morph. + expect(morphCode).not.toContain(""); rerender( rendererElement({ @@ -210,7 +219,7 @@ describe("OpenGenUIActivityRenderer", () => { }) ); await act(async () => { - await new Promise((r) => setTimeout(r, 1100)); + await new Promise((r) => setTimeout(r, THROTTLE_MS + 100)); }); await flushImport(); @@ -258,6 +267,41 @@ describe("OpenGenUIActivityRenderer", () => { expect(generatedHtmlIdx).toBeGreaterThan(generatedCssIdx); }); + it("injects a CSP meta limiting script/connect origins to the four-CDN allowlist", async () => { + renderRenderer({ + html: ['
Done
'], + htmlComplete: true, + generating: false, + }); + await flushImport(); + + expect(mockCreate).toHaveBeenCalledTimes(1); + const [, options] = mockCreate.mock.calls[0]!; + const frameContent = options.frameContent as string; + + const cspMatch = frameContent.match( + // + ); + expect(cspMatch).not.toBeNull(); + const csp = cspMatch![1]!; + expect(csp).toContain("default-src 'self'"); + const scriptSrc = csp.match(/script-src[\s\S]*?;/)![0]; + const connectSrc = csp.match(/connect-src[\s\S]*?;/)![0]; + for (const origin of [ + "https://cdnjs.cloudflare.com", + "https://esm.sh", + "https://cdn.jsdelivr.net", + "https://unpkg.com", + ]) { + expect(scriptSrc).toContain(origin); + expect(connectSrc).toContain(origin); + } + // CSP precedes any generated content. + expect(frameContent.indexOf("Content-Security-Policy")).toBeLessThan( + frameContent.indexOf('
') + ); + }); + it("ensures a exists and still injects head content first when html has none", async () => { renderRenderer({ css: "body{--marker:gen-css}", @@ -363,6 +407,76 @@ describe("OpenGenUIActivityRenderer", () => { expect(div.style.height).toBe("333px"); }); + it("ignores __ogui_resize messages from foreign sources", async () => { + renderRenderer({ + initialHeight: 200, + html: ["
Done
"], + htmlComplete: true, + generating: false, + }); + await flushImport(); + await resolveSandboxReady(); + + const div = mockIframe.parentElement as HTMLElement; + expect(div.style.height).toBe("200px"); + + await act(async () => { + window.dispatchEvent( + new MessageEvent("message", { + data: { type: "__ogui_resize", height: 999 }, + source: window, // not the sandbox iframe's contentWindow + }) + ); + }); + expect(div.style.height).toBe("200px"); + }); + + it("clamps reported heights to the 50..4000 range and rejects non-finite values", async () => { + renderRenderer({ + initialHeight: 200, + html: ["
Done
"], + htmlComplete: true, + generating: false, + }); + await flushImport(); + await resolveSandboxReady(); + + const div = mockIframe.parentElement as HTMLElement; + const send = async (height: unknown) => { + await act(async () => { + window.dispatchEvent( + new MessageEvent("message", { + data: { type: "__ogui_resize", height }, + source: mockIframe.contentWindow, + }) + ); + }); + }; + + await send(1); + expect(div.style.height).toBe("50px"); + await send(999999); + expect(div.style.height).toBe("4000px"); + // Non-finite numbers pass a bare typeof check — they must be rejected. + await send(NaN); + expect(div.style.height).toBe("4000px"); + await send(Infinity); + expect(div.style.height).toBe("4000px"); + }); + + it("clampReportedHeight rejects non-numbers and non-finite numbers", async () => { + const { clampReportedHeight } = await import("../renderer"); + expect(clampReportedHeight(420)).toBe(420); + expect(clampReportedHeight(420.4)).toBe(421); + expect(clampReportedHeight(1)).toBe(50); + expect(clampReportedHeight(999999)).toBe(4000); + expect(clampReportedHeight(NaN)).toBeNull(); + expect(clampReportedHeight(Infinity)).toBeNull(); + expect(clampReportedHeight(-Infinity)).toBeNull(); + expect(clampReportedHeight("300")).toBeNull(); + expect(clampReportedHeight(undefined)).toBeNull(); + }); + it("installs a continuous ResizeObserver measurement script in the final sandbox", async () => { renderRenderer({ html: ["
Done
"], @@ -479,6 +593,45 @@ describe("OpenGenUIActivityRenderer", () => { expect(container.querySelector('button[title="Options"]')).not.toBeNull(); }); + it("keeps the live final sandbox iframe attached when generating flips to false after htmlComplete", async () => { + // Realistic streaming sequence: the middleware emits htmlComplete:true as + // soon as the html argument finishes parsing, and generating:false only + // later at TOOL_CALL_END — the final sandbox is created during the + // intermediate snapshot. + const { container, rerender } = renderRenderer({ + css: "body{--marker:gen-css}", + cssComplete: true, + html: ['
Done
'], + htmlComplete: true, + generating: true, + }); + await flushImport(); + await resolveSandboxReady(); + + expect(mockCreate).toHaveBeenCalledTimes(1); + const iframe = mockIframe; + expect(iframe.isConnected).toBe(true); + + rerender( + rendererElement({ + css: "body{--marker:gen-css}", + cssComplete: true, + html: ['
Done
'], + htmlComplete: true, + generating: false, + }) + ); + await flushImport(); + + // The tree shape must stay constant: no remount, no extra sandbox, the + // same iframe still in the document. + expect(mockCreate).toHaveBeenCalledTimes(1); + expect(mockDestroy).not.toHaveBeenCalled(); + expect(iframe.isConnected).toBe(true); + // And the export overlay trigger appears once complete. + expect(container.querySelector('button[title="Options"]')).not.toBeNull(); + }); + it("exposes a registration object ready for renderActivityMessages", () => { expect(OPEN_GEN_UI_ACTIVITY_RENDERER.activityType).toBe("open-generative-ui"); expect(OPEN_GEN_UI_ACTIVITY_RENDERER.render).toBe(OpenGenUIActivityRenderer); diff --git a/apps/app/src/components/generative-ui/open-generative-ui/__tests__/process-partial-html.test.ts b/apps/app/src/components/generative-ui/open-generative-ui/__tests__/process-partial-html.test.ts new file mode 100644 index 0000000..bcb92cf --- /dev/null +++ b/apps/app/src/components/generative-ui/open-generative-ui/__tests__/process-partial-html.test.ts @@ -0,0 +1,90 @@ +import { describe, it, expect } from "vitest"; +import { + extractCompleteStyles, + processPartialHtml, +} from "../process-partial-html"; + +describe("processPartialHtml", () => { + it("strips an incomplete trailing tag", () => { + expect(processPartialHtml("
Hello
Hello
" + ); + expect(processPartialHtml("
Hello
<")).toBe("
Hello
"); + }); + + it("strips complete
Hi
") + ).toBe("
Hi
"); + }); + + it("strips unterminated
x
"; + expect(extractCompleteStyles(html)).toBe( + "" + ); + }); + + it("ignores unterminated style blocks", () => { + expect(extractCompleteStyles("`; const OVERFLOW_HIDDEN_STYLE_TAG = ""; +// CSP for the final sandbox document, carried over from the legacy widget +// renderer shell and matching the CDN allowlist documented in the +// advanced-visualization skill ("CSP-enforced"). 'unsafe-inline' covers the +// websandbox bootstrap and sandbox.run-injected scripts; script-src and +// connect-src are restricted to the four CDN origins so generated code cannot +// load from or exfiltrate to arbitrary origins. +export const CSP_META_TAG = ``; + export function ensureHead(html: string): string { if (/]/i.test(html)) return html; return `${html}`; } /** - * Final sandbox document: importmap first (must precede any scripts so module - * resolution works), then design-system styles, then the generated css, then - * the generated html. Head content is injected right after the opening - * tag so it precedes anything the generated document put in its own head. + * Final sandbox document: CSP meta first, then importmap (must precede any + * scripts so module resolution works), then design-system styles, then the + * generated css, then the generated html. Head content is injected right + * after the opening tag so it precedes anything the generated document + * put in its own head. */ export function buildFinalFrameContent(html: string, css?: string): string { const headContent = + CSP_META_TAG + IMPORTMAP_SCRIPT_TAG + DESIGN_SYSTEM_STYLE_TAG + (css ? `` : ""); @@ -56,14 +81,30 @@ export function buildPreviewHeadContent( /** * Preview body update: morph via Idiomorph (preserves existing nodes, no * flicker), falling back to a plain innerHTML assignment if Idiomorph is - * unavailable or throws. + * unavailable or throws. New element nodes are tagged with morph-enter + * (legacy bridge parity) so the design system's fadeSlideIn animation plays + * as streamed content appears. (The #content.initial-render stagger rules in + * FORM_STYLES_WITH_STAGGER_CSS apply only to documents that wrap content in + * #content — i.e. the MCP rail — and are inert here.) */ export function buildPreviewBodyMorph(body: string): string { return `(function() { var html = ${JSON.stringify(body)}; if (typeof Idiomorph !== "undefined" && Idiomorph && Idiomorph.morph) { try { - Idiomorph.morph(document.body, html, { morphStyle: 'innerHTML' }); + Idiomorph.morph(document.body, html, { + morphStyle: 'innerHTML', + callbacks: { + beforeNodeAdded: function(node) { + if (node.nodeType === 1) { + node.classList.add('morph-enter'); + node.addEventListener('animationend', function() { + node.classList.remove('morph-enter'); + }, { once: true }); + } + } + } + }); } catch (err) { document.body.innerHTML = html; } diff --git a/apps/app/src/components/generative-ui/open-generative-ui/renderer.tsx b/apps/app/src/components/generative-ui/open-generative-ui/renderer.tsx index 3e944a9..4fb3a40 100644 --- a/apps/app/src/components/generative-ui/open-generative-ui/renderer.tsx +++ b/apps/app/src/components/generative-ui/open-generative-ui/renderer.tsx @@ -17,10 +17,20 @@ import { import { extractCompleteStyles, processPartialHtml } from "./process-partial-html"; import { loadWebsandbox, type SandboxInstance } from "./websandbox-loader"; -const THROTTLE_MS = 1000; +export const THROTTLE_MS = 1000; const MIN_HEIGHT = 50; const MAX_HEIGHT = 4000; +/** + * Clamp a sandbox-reported height to the allowed range. Returns null for + * anything that is not a finite number (NaN/Infinity pass a bare typeof + * check and would otherwise poison the container height). + */ +export function clampReportedHeight(height: unknown): number | null { + if (typeof height !== "number" || !Number.isFinite(height)) return null; + return Math.max(MIN_HEIGHT, Math.min(Math.ceil(height), MAX_HEIGHT)); +} + export const LOADING_PHRASES = [ "Sketching pixels", "Wiring up nodes", @@ -258,12 +268,10 @@ const OpenGenUIActivityRendererInner = React.memo( if (!sandbox) return; if ( e.source === sandbox.iframe.contentWindow && - e.data?.type === RESIZE_MESSAGE_TYPE && - typeof e.data.height === "number" + e.data?.type === RESIZE_MESSAGE_TYPE ) { - setAutoHeight( - Math.max(MIN_HEIGHT, Math.min(Math.ceil(e.data.height), MAX_HEIGHT)) - ); + const clamped = clampReportedHeight(e.data.height); + if (clamped !== null) setAutoHeight(clamped); } }; window.addEventListener("message", onMessage); @@ -440,13 +448,16 @@ const OpenGenUIActivityRendererInner = React.memo(
); - if (!isComplete) return frame; - + // Always wrap in ExportOverlay so the rendered tree shape never changes: + // switching the root from the bare frame div to a wrapper when isComplete + // flips would remount the container and silently destroy the live + // websandbox iframe created during the htmlComplete && generating window. return ( {frame} diff --git a/apps/app/src/components/template-library/__tests__/seed-templates.test.ts b/apps/app/src/components/template-library/__tests__/seed-templates.test.ts new file mode 100644 index 0000000..092e6ef --- /dev/null +++ b/apps/app/src/components/template-library/__tests__/seed-templates.test.ts @@ -0,0 +1,28 @@ +import { describe, it, expect } from "vitest"; +import { SEED_TEMPLATES, SEED_IDS } from "../seed-templates"; + +describe("seed templates", () => { + it("covers exactly the three seed ids", () => { + expect(SEED_TEMPLATES.map((t) => t.id).sort()).toEqual( + [...SEED_IDS].sort() + ); + for (const t of SEED_TEMPLATES) { + expect(t.html.trim()).not.toBe(""); + } + }); + + it("never uses the retired global sendPrompt('...') idiom", () => { + // Inside the websandbox iframe there is no global sendPrompt — only the + // RPC bridge. Seeds are handed to the model as style references, so a + // legacy idiom here teaches the model to emit dead buttons. + for (const t of SEED_TEMPLATES) { + expect(t.html).not.toContain("sendPrompt('"); + expect(t.html).not.toContain('sendPrompt("'); + } + }); + + it("wires interactive buttons through the sandbox bridge", () => { + const invoice = SEED_TEMPLATES.find((t) => t.id === "seed-invoice-001")!; + expect(invoice.html).toContain("Websandbox.connection.remote.sendPrompt({ text:"); + }); +}); diff --git a/apps/app/src/components/template-library/seed-templates.ts b/apps/app/src/components/template-library/seed-templates.ts index 847eb46..cd831c5 100644 --- a/apps/app/src/components/template-library/seed-templates.ts +++ b/apps/app/src/components/template-library/seed-templates.ts @@ -122,8 +122,8 @@ const invoiceHtml = `