diff --git a/apps/dev-playground/.env.dist b/apps/dev-playground/.env.dist
index 7a7076ff..e17b89d5 100644
--- a/apps/dev-playground/.env.dist
+++ b/apps/dev-playground/.env.dist
@@ -6,3 +6,4 @@ NODE_ENV='development'
OTEL_EXPORTER_OTLP_ENDPOINT='http://localhost:4318'
OTEL_RESOURCE_ATTRIBUTES='service.sample_attribute=dev'
OTEL_SERVICE_NAME='dev-playground'
+GENIE_SPACE_ID=
diff --git a/apps/dev-playground/client/src/routeTree.gen.ts b/apps/dev-playground/client/src/routeTree.gen.ts
index f9b31113..904e257b 100644
--- a/apps/dev-playground/client/src/routeTree.gen.ts
+++ b/apps/dev-playground/client/src/routeTree.gen.ts
@@ -13,6 +13,7 @@ import { Route as TypeSafetyRouteRouteImport } from './routes/type-safety.route'
import { Route as TelemetryRouteRouteImport } from './routes/telemetry.route'
import { Route as SqlHelpersRouteRouteImport } from './routes/sql-helpers.route'
import { Route as ReconnectRouteRouteImport } from './routes/reconnect.route'
+import { Route as GenieRouteRouteImport } from './routes/genie.route'
import { Route as DataVisualizationRouteRouteImport } from './routes/data-visualization.route'
import { Route as ArrowAnalyticsRouteRouteImport } from './routes/arrow-analytics.route'
import { Route as AnalyticsRouteRouteImport } from './routes/analytics.route'
@@ -38,6 +39,11 @@ const ReconnectRouteRoute = ReconnectRouteRouteImport.update({
path: '/reconnect',
getParentRoute: () => rootRouteImport,
} as any)
+const GenieRouteRoute = GenieRouteRouteImport.update({
+ id: '/genie',
+ path: '/genie',
+ getParentRoute: () => rootRouteImport,
+} as any)
const DataVisualizationRouteRoute = DataVisualizationRouteRouteImport.update({
id: '/data-visualization',
path: '/data-visualization',
@@ -64,6 +70,7 @@ export interface FileRoutesByFullPath {
'/analytics': typeof AnalyticsRouteRoute
'/arrow-analytics': typeof ArrowAnalyticsRouteRoute
'/data-visualization': typeof DataVisualizationRouteRoute
+ '/genie': typeof GenieRouteRoute
'/reconnect': typeof ReconnectRouteRoute
'/sql-helpers': typeof SqlHelpersRouteRoute
'/telemetry': typeof TelemetryRouteRoute
@@ -74,6 +81,7 @@ export interface FileRoutesByTo {
'/analytics': typeof AnalyticsRouteRoute
'/arrow-analytics': typeof ArrowAnalyticsRouteRoute
'/data-visualization': typeof DataVisualizationRouteRoute
+ '/genie': typeof GenieRouteRoute
'/reconnect': typeof ReconnectRouteRoute
'/sql-helpers': typeof SqlHelpersRouteRoute
'/telemetry': typeof TelemetryRouteRoute
@@ -85,6 +93,7 @@ export interface FileRoutesById {
'/analytics': typeof AnalyticsRouteRoute
'/arrow-analytics': typeof ArrowAnalyticsRouteRoute
'/data-visualization': typeof DataVisualizationRouteRoute
+ '/genie': typeof GenieRouteRoute
'/reconnect': typeof ReconnectRouteRoute
'/sql-helpers': typeof SqlHelpersRouteRoute
'/telemetry': typeof TelemetryRouteRoute
@@ -97,6 +106,7 @@ export interface FileRouteTypes {
| '/analytics'
| '/arrow-analytics'
| '/data-visualization'
+ | '/genie'
| '/reconnect'
| '/sql-helpers'
| '/telemetry'
@@ -107,6 +117,7 @@ export interface FileRouteTypes {
| '/analytics'
| '/arrow-analytics'
| '/data-visualization'
+ | '/genie'
| '/reconnect'
| '/sql-helpers'
| '/telemetry'
@@ -117,6 +128,7 @@ export interface FileRouteTypes {
| '/analytics'
| '/arrow-analytics'
| '/data-visualization'
+ | '/genie'
| '/reconnect'
| '/sql-helpers'
| '/telemetry'
@@ -128,6 +140,7 @@ export interface RootRouteChildren {
AnalyticsRouteRoute: typeof AnalyticsRouteRoute
ArrowAnalyticsRouteRoute: typeof ArrowAnalyticsRouteRoute
DataVisualizationRouteRoute: typeof DataVisualizationRouteRoute
+ GenieRouteRoute: typeof GenieRouteRoute
ReconnectRouteRoute: typeof ReconnectRouteRoute
SqlHelpersRouteRoute: typeof SqlHelpersRouteRoute
TelemetryRouteRoute: typeof TelemetryRouteRoute
@@ -164,6 +177,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof ReconnectRouteRouteImport
parentRoute: typeof rootRouteImport
}
+ '/genie': {
+ id: '/genie'
+ path: '/genie'
+ fullPath: '/genie'
+ preLoaderRoute: typeof GenieRouteRouteImport
+ parentRoute: typeof rootRouteImport
+ }
'/data-visualization': {
id: '/data-visualization'
path: '/data-visualization'
@@ -200,6 +220,7 @@ const rootRouteChildren: RootRouteChildren = {
AnalyticsRouteRoute: AnalyticsRouteRoute,
ArrowAnalyticsRouteRoute: ArrowAnalyticsRouteRoute,
DataVisualizationRouteRoute: DataVisualizationRouteRoute,
+ GenieRouteRoute: GenieRouteRoute,
ReconnectRouteRoute: ReconnectRouteRoute,
SqlHelpersRouteRoute: SqlHelpersRouteRoute,
TelemetryRouteRoute: TelemetryRouteRoute,
diff --git a/apps/dev-playground/client/src/routes/__root.tsx b/apps/dev-playground/client/src/routes/__root.tsx
index b2faa651..3ad7ca0c 100644
--- a/apps/dev-playground/client/src/routes/__root.tsx
+++ b/apps/dev-playground/client/src/routes/__root.tsx
@@ -72,6 +72,14 @@ function RootComponent() {
SQL Helpers
+
+
+
diff --git a/apps/dev-playground/client/src/routes/genie.route.tsx b/apps/dev-playground/client/src/routes/genie.route.tsx
new file mode 100644
index 00000000..3b47ce37
--- /dev/null
+++ b/apps/dev-playground/client/src/routes/genie.route.tsx
@@ -0,0 +1,29 @@
+import { GenieChat } from "@databricks/appkit-ui/react";
+import { createFileRoute } from "@tanstack/react-router";
+
+export const Route = createFileRoute("/genie")({
+ component: GenieRoute,
+});
+
+function GenieRoute() {
+ return (
+
diff --git a/apps/dev-playground/server/index.ts b/apps/dev-playground/server/index.ts
index a56ba4a7..4da9295b 100644
--- a/apps/dev-playground/server/index.ts
+++ b/apps/dev-playground/server/index.ts
@@ -1,4 +1,4 @@
-import { analytics, createApp, server } from "@databricks/appkit";
+import { analytics, createApp, genie, server } from "@databricks/appkit";
import { WorkspaceClient } from "@databricks/sdk-experimental";
import { reconnect } from "./reconnect-plugin";
import { telemetryExamples } from "./telemetry-example-plugin";
@@ -19,6 +19,9 @@ createApp({
reconnect(),
telemetryExamples(),
analytics({}),
+ genie({
+ spaces: { demo: process.env.GENIE_SPACE_ID ?? "placeholder" },
+ }),
],
...(process.env.APPKIT_E2E_TEST && { client: createMockClient() }),
}).then((appkit) => {
diff --git a/docs/static/appkit-ui/styles.gen.css b/docs/static/appkit-ui/styles.gen.css
index a9f095f5..5a11e82f 100644
--- a/docs/static/appkit-ui/styles.gen.css
+++ b/docs/static/appkit-ui/styles.gen.css
@@ -8,7 +8,42 @@
"Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
"Courier New", monospace;
+ --color-red-50: oklch(97.1% 0.013 17.38);
+ --color-red-100: oklch(93.6% 0.032 17.717);
+ --color-red-200: oklch(88.5% 0.062 18.334);
+ --color-red-700: oklch(50.5% 0.213 27.518);
+ --color-amber-500: oklch(76.9% 0.188 70.08);
+ --color-yellow-100: oklch(97.3% 0.071 103.193);
+ --color-yellow-200: oklch(94.5% 0.129 101.54);
+ --color-yellow-300: oklch(90.5% 0.182 98.111);
+ --color-yellow-600: oklch(68.1% 0.162 75.834);
+ --color-yellow-700: oklch(55.4% 0.135 66.442);
+ --color-green-50: oklch(98.2% 0.018 155.826);
+ --color-green-100: oklch(96.2% 0.044 156.743);
+ --color-green-200: oklch(92.5% 0.084 155.995);
+ --color-green-400: oklch(79.2% 0.209 151.711);
+ --color-green-500: oklch(72.3% 0.219 149.579);
+ --color-green-600: oklch(62.7% 0.194 149.214);
+ --color-green-700: oklch(52.7% 0.154 150.069);
+ --color-emerald-100: oklch(95% 0.052 163.051);
+ --color-emerald-200: oklch(90.5% 0.093 164.15);
+ --color-emerald-700: oklch(50.8% 0.118 165.612);
--color-sky-500: oklch(68.5% 0.169 237.323);
+ --color-blue-100: oklch(93.2% 0.032 255.585);
+ --color-blue-200: oklch(88.2% 0.059 254.128);
+ --color-blue-600: oklch(54.6% 0.245 262.881);
+ --color-blue-700: oklch(48.8% 0.243 264.376);
+ --color-blue-800: oklch(42.4% 0.199 265.638);
+ --color-gray-50: oklch(98.5% 0.002 247.839);
+ --color-gray-100: oklch(96.7% 0.003 264.542);
+ --color-gray-200: oklch(92.8% 0.006 264.531);
+ --color-gray-400: oklch(70.7% 0.022 261.325);
+ --color-gray-500: oklch(55.1% 0.027 264.364);
+ --color-gray-600: oklch(44.6% 0.03 256.802);
+ --color-gray-700: oklch(37.3% 0.034 259.733);
+ --color-gray-800: oklch(27.8% 0.033 256.848);
+ --color-gray-900: oklch(21% 0.034 264.665);
+ --color-zinc-900: oklch(21% 0.006 285.885);
--color-black: #000;
--color-white: #fff;
--spacing: 0.25rem;
@@ -16,6 +51,10 @@
--container-sm: 24rem;
--container-md: 28rem;
--container-lg: 32rem;
+ --container-2xl: 42rem;
+ --container-4xl: 56rem;
+ --container-6xl: 72rem;
+ --container-7xl: 80rem;
--text-xs: 0.75rem;
--text-xs--line-height: calc(1 / 0.75);
--text-sm: 0.875rem;
@@ -24,10 +63,16 @@
--text-base--line-height: calc(1.5 / 1);
--text-lg: 1.125rem;
--text-lg--line-height: calc(1.75 / 1.125);
+ --text-xl: 1.25rem;
+ --text-xl--line-height: calc(1.75 / 1.25);
--text-2xl: 1.5rem;
--text-2xl--line-height: calc(2 / 1.5);
+ --text-3xl: 1.875rem;
+ --text-3xl--line-height: calc(2.25 / 1.875);
--text-4xl: 2.25rem;
--text-4xl--line-height: calc(2.5 / 2.25);
+ --text-5xl: 3rem;
+ --text-5xl--line-height: 1;
--text-7xl: 4.5rem;
--text-7xl--line-height: 1;
--font-weight-normal: 400;
@@ -46,6 +91,7 @@
--radius-md: 0.375rem;
--radius-lg: 0.5rem;
--radius-xl: 0.75rem;
+ --ease-out: cubic-bezier(0, 0, 0.2, 1);
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
--animate-spin: spin 1s linear infinite;
--animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
@@ -283,9 +329,15 @@
.top-\[50\%\] {
top: 50%;
}
+ .top-\[52px\] {
+ top: 52px;
+ }
.top-\[60\%\] {
top: 60%;
}
+ .top-\[84px\] {
+ top: 84px;
+ }
.top-full {
top: 100%;
}
@@ -307,12 +359,18 @@
.right-4 {
right: calc(var(--spacing) * 4);
}
+ .right-8 {
+ right: calc(var(--spacing) * 8);
+ }
.-bottom-12 {
bottom: calc(var(--spacing) * -12);
}
.bottom-0 {
bottom: calc(var(--spacing) * 0);
}
+ .bottom-\[24px\] {
+ bottom: 24px;
+ }
.-left-12 {
left: calc(var(--spacing) * -12);
}
@@ -325,12 +383,27 @@
.left-2 {
left: calc(var(--spacing) * 2);
}
+ .left-8 {
+ left: calc(var(--spacing) * 8);
+ }
.left-\[50\%\] {
left: 50%;
}
+ .left-\[88px\] {
+ left: 88px;
+ }
+ .left-\[100px\] {
+ left: 100px;
+ }
+ .left-\[220px\] {
+ left: 220px;
+ }
.isolate {
isolation: isolate;
}
+ .z-0 {
+ z-index: 0;
+ }
.z-10 {
z-index: 10;
}
@@ -358,6 +431,21 @@
.col-start-2 {
grid-column-start: 2;
}
+ .row-1 {
+ grid-row: 1;
+ }
+ .row-2 {
+ grid-row: 2;
+ }
+ .row-3 {
+ grid-row: 3;
+ }
+ .row-4 {
+ grid-row: 4;
+ }
+ .row-5 {
+ grid-row: 5;
+ }
.row-span-2 {
grid-row: span 2 / span 2;
}
@@ -388,12 +476,18 @@
.\!m-0 {
margin: calc(var(--spacing) * 0) !important;
}
+ .m-4 {
+ margin: calc(var(--spacing) * 4);
+ }
.-mx-1 {
margin-inline: calc(var(--spacing) * -1);
}
.mx-2 {
margin-inline: calc(var(--spacing) * 2);
}
+ .mx-3 {
+ margin-inline: calc(var(--spacing) * 3);
+ }
.mx-3\.5 {
margin-inline: calc(var(--spacing) * 3.5);
}
@@ -421,6 +515,9 @@
.-mt-4 {
margin-top: calc(var(--spacing) * -4);
}
+ .mt-1 {
+ margin-top: calc(var(--spacing) * 1);
+ }
.mt-1\.5 {
margin-top: calc(var(--spacing) * 1.5);
}
@@ -433,12 +530,18 @@
.mt-4 {
margin-top: calc(var(--spacing) * 4);
}
+ .mt-8 {
+ margin-top: calc(var(--spacing) * 8);
+ }
.mt-auto {
margin-top: auto;
}
.mr-2 {
margin-right: calc(var(--spacing) * 2);
}
+ .mb-1 {
+ margin-bottom: calc(var(--spacing) * 1);
+ }
.mb-2 {
margin-bottom: calc(var(--spacing) * 2);
}
@@ -448,6 +551,15 @@
.mb-4 {
margin-bottom: calc(var(--spacing) * 4);
}
+ .mb-6 {
+ margin-bottom: calc(var(--spacing) * 6);
+ }
+ .mb-8 {
+ margin-bottom: calc(var(--spacing) * 8);
+ }
+ .mb-16 {
+ margin-bottom: calc(var(--spacing) * 16);
+ }
.-ml-4 {
margin-left: calc(var(--spacing) * -4);
}
@@ -460,6 +572,9 @@
.ml-4 {
margin-left: calc(var(--spacing) * 4);
}
+ .ml-5 {
+ margin-left: calc(var(--spacing) * 5);
+ }
.ml-auto {
margin-left: auto;
}
@@ -572,6 +687,9 @@
.h-\(--cell-size\) {
height: var(--cell-size);
}
+ .h-0\.5 {
+ height: calc(var(--spacing) * 0.5);
+ }
.h-1\.5 {
height: calc(var(--spacing) * 1.5);
}
@@ -581,6 +699,9 @@
.h-2\.5 {
height: calc(var(--spacing) * 2.5);
}
+ .h-3 {
+ height: calc(var(--spacing) * 3);
+ }
.h-4 {
height: calc(var(--spacing) * 4);
}
@@ -605,6 +726,9 @@
.h-12 {
height: calc(var(--spacing) * 12);
}
+ .h-20 {
+ height: calc(var(--spacing) * 20);
+ }
.h-24 {
height: calc(var(--spacing) * 24);
}
@@ -623,6 +747,9 @@
.h-\[200px\] {
height: 200px;
}
+ .h-\[600px\] {
+ height: 600px;
+ }
.h-\[calc\(100\%-1px\)\] {
height: calc(100% - 1px);
}
@@ -653,9 +780,15 @@
.max-h-\(--radix-select-content-available-height\) {
max-height: var(--radix-select-content-available-height);
}
+ .max-h-96 {
+ max-height: calc(var(--spacing) * 96);
+ }
.max-h-\[300px\] {
max-height: 300px;
}
+ .max-h-\[400px\] {
+ max-height: 400px;
+ }
.max-h-\[600px\] {
max-height: 600px;
}
@@ -668,6 +801,15 @@
.min-h-16 {
min-height: calc(var(--spacing) * 16);
}
+ .min-h-\[300px\] {
+ min-height: 300px;
+ }
+ .min-h-\[400px\] {
+ min-height: 400px;
+ }
+ .min-h-screen {
+ min-height: 100vh;
+ }
.min-h-svh {
min-height: 100svh;
}
@@ -683,12 +825,18 @@
.w-1 {
width: calc(var(--spacing) * 1);
}
+ .w-1\/2 {
+ width: calc(1/2 * 100%);
+ }
.w-2 {
width: calc(var(--spacing) * 2);
}
.w-2\.5 {
width: calc(var(--spacing) * 2.5);
}
+ .w-2\/3 {
+ width: calc(2/3 * 100%);
+ }
.w-3 {
width: calc(var(--spacing) * 3);
}
@@ -698,6 +846,9 @@
.w-4 {
width: calc(var(--spacing) * 4);
}
+ .w-4\/5 {
+ width: calc(4/5 * 100%);
+ }
.w-5 {
width: calc(var(--spacing) * 5);
}
@@ -707,6 +858,9 @@
.w-9 {
width: calc(var(--spacing) * 9);
}
+ .w-10 {
+ width: calc(var(--spacing) * 10);
+ }
.w-12 {
width: calc(var(--spacing) * 12);
}
@@ -716,6 +870,9 @@
.w-24 {
width: calc(var(--spacing) * 24);
}
+ .w-28 {
+ width: calc(var(--spacing) * 28);
+ }
.w-32 {
width: calc(var(--spacing) * 32);
}
@@ -725,6 +882,9 @@
.w-56 {
width: calc(var(--spacing) * 56);
}
+ .w-60 {
+ width: calc(var(--spacing) * 60);
+ }
.w-64 {
width: calc(var(--spacing) * 64);
}
@@ -746,6 +906,12 @@
.w-\[100px\] {
width: 100px;
}
+ .w-\[130px\] {
+ width: 130px;
+ }
+ .w-\[150px\] {
+ width: 150px;
+ }
.w-\[180px\] {
width: 180px;
}
@@ -785,9 +951,30 @@
.max-w-\(--skeleton-width\) {
max-width: var(--skeleton-width);
}
+ .max-w-2xl {
+ max-width: var(--container-2xl);
+ }
+ .max-w-4xl {
+ max-width: var(--container-4xl);
+ }
+ .max-w-6xl {
+ max-width: var(--container-6xl);
+ }
+ .max-w-7xl {
+ max-width: var(--container-7xl);
+ }
+ .max-w-\[80\%\] {
+ max-width: 80%;
+ }
+ .max-w-\[1200px\] {
+ max-width: 1200px;
+ }
.max-w-\[calc\(100\%-2rem\)\] {
max-width: calc(100% - 2rem);
}
+ .max-w-full {
+ max-width: 100%;
+ }
.max-w-max {
max-width: max-content;
}
@@ -836,6 +1023,9 @@
.shrink-0 {
flex-shrink: 0;
}
+ .flex-grow {
+ flex-grow: 1;
+ }
.grow {
flex-grow: 1;
}
@@ -932,6 +1122,9 @@
.cursor-default {
cursor: default;
}
+ .cursor-pointer {
+ cursor: pointer;
+ }
.cursor-text {
cursor: text;
}
@@ -956,6 +1149,9 @@
.auto-rows-min {
grid-auto-rows: min-content;
}
+ .grid-cols-1 {
+ grid-template-columns: repeat(1, minmax(0, 1fr));
+ }
.grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
@@ -983,6 +1179,9 @@
.flex-row {
flex-direction: row;
}
+ .flex-row-reverse {
+ flex-direction: row-reverse;
+ }
.flex-wrap {
flex-wrap: wrap;
}
@@ -1037,6 +1236,9 @@
.gap-4 {
gap: calc(var(--spacing) * 4);
}
+ .gap-5 {
+ gap: calc(var(--spacing) * 5);
+ }
.gap-6 {
gap: calc(var(--spacing) * 6);
}
@@ -1067,6 +1269,20 @@
margin-block-end: calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)));
}
}
+ .space-y-4 {
+ :where(& > :not(:last-child)) {
+ --tw-space-y-reverse: 0;
+ margin-block-start: calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));
+ margin-block-end: calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)));
+ }
+ }
+ .space-y-6 {
+ :where(& > :not(:last-child)) {
+ --tw-space-y-reverse: 0;
+ margin-block-start: calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));
+ margin-block-end: calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)));
+ }
+ }
.space-x-2 {
:where(& > :not(:last-child)) {
--tw-space-x-reverse: 0;
@@ -1084,6 +1300,9 @@
.gap-y-0\.5 {
row-gap: calc(var(--spacing) * 0.5);
}
+ .self-end {
+ align-self: flex-end;
+ }
.self-start {
align-self: flex-start;
}
@@ -1168,6 +1387,14 @@
border-style: var(--tw-border-style);
border-width: 0px;
}
+ .border-2 {
+ border-style: var(--tw-border-style);
+ border-width: 2px;
+ }
+ .border-3 {
+ border-style: var(--tw-border-style);
+ border-width: 3px;
+ }
.border-\[1\.5px\] {
border-style: var(--tw-border-style);
border-width: 1.5px;
@@ -1199,6 +1426,12 @@
.border-\(--color-border\) {
border-color: var(--color-border);
}
+ .border-\[\#454545\] {
+ border-color: #454545;
+ }
+ .border-blue-200 {
+ border-color: var(--color-blue-200);
+ }
.border-border {
border-color: var(--border);
}
@@ -1208,18 +1441,54 @@
border-color: color-mix(in oklab, var(--border) 50%, transparent);
}
}
+ .border-destructive\/20 {
+ border-color: var(--destructive);
+ @supports (color: color-mix(in lab, red, red)) {
+ border-color: color-mix(in oklab, var(--destructive) 20%, transparent);
+ }
+ }
+ .border-emerald-200 {
+ border-color: var(--color-emerald-200);
+ }
+ .border-gray-200 {
+ border-color: var(--color-gray-200);
+ }
+ .border-gray-400 {
+ border-color: var(--color-gray-400);
+ }
+ .border-green-200 {
+ border-color: var(--color-green-200);
+ }
+ .border-green-600 {
+ border-color: var(--color-green-600);
+ }
.border-input {
border-color: var(--input);
}
.border-primary {
border-color: var(--primary);
}
+ .border-red-200 {
+ border-color: var(--color-red-200);
+ }
.border-sidebar-border {
border-color: var(--sidebar-border);
}
+ .border-success\/20 {
+ border-color: var(--success);
+ @supports (color: color-mix(in lab, red, red)) {
+ border-color: color-mix(in oklab, var(--success) 20%, transparent);
+ }
+ }
.border-transparent {
border-color: transparent;
}
+ .border-yellow-200 {
+ border-color: var(--color-yellow-200);
+ }
+ .border-yellow-600 {
+ border-color: var(--color-yellow-600);
+ }
.border-t-transparent {
border-top-color: transparent;
}
@@ -1229,9 +1498,18 @@
.bg-\(--color-bg\) {
background-color: var(--color-bg);
}
+ .bg-\[\#04395e\] {
+ background-color: #04395e;
+ }
+ .bg-\[\#252526\] {
+ background-color: #252526;
+ }
.bg-accent {
background-color: var(--accent);
}
+ .bg-amber-500 {
+ background-color: var(--color-amber-500);
+ }
.bg-background {
background-color: var(--background);
}
@@ -1241,6 +1519,9 @@
background-color: color-mix(in oklab, var(--color-black) 50%, transparent);
}
}
+ .bg-blue-100 {
+ background-color: var(--color-blue-100);
+ }
.bg-border {
background-color: var(--border);
}
@@ -1250,15 +1531,51 @@
.bg-destructive {
background-color: var(--destructive);
}
+ .bg-destructive\/10 {
+ background-color: var(--destructive);
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--destructive) 10%, transparent);
+ }
+ }
+ .bg-emerald-100 {
+ background-color: var(--color-emerald-100);
+ }
.bg-foreground {
background-color: var(--foreground);
}
+ .bg-gray-50 {
+ background-color: var(--color-gray-50);
+ }
+ .bg-gray-100 {
+ background-color: var(--color-gray-100);
+ }
+ .bg-gray-200 {
+ background-color: var(--color-gray-200);
+ }
+ .bg-gray-800 {
+ background-color: var(--color-gray-800);
+ }
+ .bg-green-50 {
+ background-color: var(--color-green-50);
+ }
+ .bg-green-100 {
+ background-color: var(--color-green-100);
+ }
+ .bg-green-400 {
+ background-color: var(--color-green-400);
+ }
.bg-input {
background-color: var(--input);
}
.bg-muted {
background-color: var(--muted);
}
+ .bg-muted-foreground\/40 {
+ background-color: var(--muted-foreground);
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--muted-foreground) 40%, transparent);
+ }
+ }
.bg-muted\/50 {
background-color: var(--muted);
@supports (color: color-mix(in lab, red, red)) {
@@ -1277,6 +1594,12 @@
background-color: color-mix(in oklab, var(--primary) 20%, transparent);
}
}
+ .bg-red-50 {
+ background-color: var(--color-red-50);
+ }
+ .bg-red-100 {
+ background-color: var(--color-red-100);
+ }
.bg-secondary {
background-color: var(--secondary);
}
@@ -1289,12 +1612,33 @@
.bg-sky-500 {
background-color: var(--color-sky-500);
}
+ .bg-success {
+ background-color: var(--success);
+ }
+ .bg-success\/10 {
+ background-color: var(--success);
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--success) 10%, transparent);
+ }
+ }
.bg-transparent {
background-color: transparent;
}
.bg-white {
background-color: var(--color-white);
}
+ .bg-white\/90 {
+ background-color: color-mix(in srgb, #fff 90%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--color-white) 90%, transparent);
+ }
+ }
+ .bg-yellow-100 {
+ background-color: var(--color-yellow-100);
+ }
+ .bg-yellow-300 {
+ background-color: var(--color-yellow-300);
+ }
.bg-gradient-to-b {
--tw-gradient-position: to bottom in oklab;
background-image: linear-gradient(var(--tw-gradient-stops));
@@ -1337,12 +1681,18 @@
.p-4 {
padding: calc(var(--spacing) * 4);
}
+ .p-5 {
+ padding: calc(var(--spacing) * 5);
+ }
.p-6 {
padding: calc(var(--spacing) * 6);
}
.p-8 {
padding: calc(var(--spacing) * 8);
}
+ .p-10 {
+ padding: calc(var(--spacing) * 10);
+ }
.p-\[3px\] {
padding: 3px;
}
@@ -1373,6 +1723,12 @@
.px-6 {
padding-inline: calc(var(--spacing) * 6);
}
+ .px-11 {
+ padding-inline: calc(var(--spacing) * 11);
+ }
+ .px-\[1px\] {
+ padding-inline: 1px;
+ }
.py-0\.5 {
padding-block: calc(var(--spacing) * 0.5);
}
@@ -1394,6 +1750,12 @@
.py-6 {
padding-block: calc(var(--spacing) * 6);
}
+ .py-12 {
+ padding-block: calc(var(--spacing) * 12);
+ }
+ .py-20 {
+ padding-block: calc(var(--spacing) * 20);
+ }
.pt-0 {
padding-top: calc(var(--spacing) * 0);
}
@@ -1406,6 +1768,12 @@
.pt-4 {
padding-top: calc(var(--spacing) * 4);
}
+ .pt-6 {
+ padding-top: calc(var(--spacing) * 6);
+ }
+ .pt-12 {
+ padding-top: calc(var(--spacing) * 12);
+ }
.pr-1 {
padding-right: calc(var(--spacing) * 1);
}
@@ -1424,6 +1792,9 @@
.pb-0 {
padding-bottom: calc(var(--spacing) * 0);
}
+ .pb-2 {
+ padding-bottom: calc(var(--spacing) * 2);
+ }
.pb-3 {
padding-bottom: calc(var(--spacing) * 3);
}
@@ -1464,10 +1835,18 @@
font-size: var(--text-2xl);
line-height: var(--tw-leading, var(--text-2xl--line-height));
}
+ .text-3xl {
+ font-size: var(--text-3xl);
+ line-height: var(--tw-leading, var(--text-3xl--line-height));
+ }
.text-4xl {
font-size: var(--text-4xl);
line-height: var(--tw-leading, var(--text-4xl--line-height));
}
+ .text-5xl {
+ font-size: var(--text-5xl);
+ line-height: var(--tw-leading, var(--text-5xl--line-height));
+ }
.text-7xl {
font-size: var(--text-7xl);
line-height: var(--tw-leading, var(--text-7xl--line-height));
@@ -1488,6 +1867,10 @@
font-size: var(--text-sm);
line-height: var(--leading-relaxed);
}
+ .text-xl {
+ font-size: var(--text-xl);
+ line-height: var(--tw-leading, var(--text-xl--line-height));
+ }
.text-xs {
font-size: var(--text-xs);
line-height: var(--tw-leading, var(--text-xs--line-height));
@@ -1498,6 +1881,13 @@
.text-\[0\.70rem\] {
font-size: 0.70rem;
}
+ .text-\[11px\] {
+ font-size: 11px;
+ }
+ .leading-7 {
+ --tw-leading: calc(var(--spacing) * 7);
+ line-height: calc(var(--spacing) * 7);
+ }
.leading-none {
--tw-leading: 1;
line-height: 1;
@@ -1551,12 +1941,27 @@
.whitespace-nowrap {
white-space: nowrap;
}
+ .whitespace-pre-wrap {
+ white-space: pre-wrap;
+ }
+ .text-\[\#858585\] {
+ color: #858585;
+ }
+ .text-\[\#cccccc\] {
+ color: #cccccc;
+ }
.text-accent-foreground {
color: var(--accent-foreground);
}
.text-background {
color: var(--background);
}
+ .text-blue-600 {
+ color: var(--color-blue-600);
+ }
+ .text-blue-700 {
+ color: var(--color-blue-700);
+ }
.text-card-foreground {
color: var(--card-foreground);
}
@@ -1566,9 +1971,39 @@
.text-destructive {
color: var(--destructive);
}
+ .text-emerald-700 {
+ color: var(--color-emerald-700);
+ }
.text-foreground {
color: var(--foreground);
}
+ .text-gray-400 {
+ color: var(--color-gray-400);
+ }
+ .text-gray-500 {
+ color: var(--color-gray-500);
+ }
+ .text-gray-600 {
+ color: var(--color-gray-600);
+ }
+ .text-gray-700 {
+ color: var(--color-gray-700);
+ }
+ .text-gray-900 {
+ color: var(--color-gray-900);
+ }
+ .text-green-400 {
+ color: var(--color-green-400);
+ }
+ .text-green-500 {
+ color: var(--color-green-500);
+ }
+ .text-green-700 {
+ color: var(--color-green-700);
+ }
+ .text-inherit {
+ color: inherit;
+ }
.text-muted-foreground {
color: var(--muted-foreground);
}
@@ -1581,6 +2016,9 @@
.text-primary-foreground {
color: var(--primary-foreground);
}
+ .text-red-700 {
+ color: var(--color-red-700);
+ }
.text-secondary-foreground {
color: var(--secondary-foreground);
}
@@ -1593,9 +2031,21 @@
color: color-mix(in oklab, var(--sidebar-foreground) 70%, transparent);
}
}
+ .text-success {
+ color: var(--success);
+ }
+ .text-warning {
+ color: var(--warning);
+ }
.text-white {
color: var(--color-white);
}
+ .text-yellow-700 {
+ color: var(--color-yellow-700);
+ }
+ .text-zinc-900 {
+ color: var(--color-zinc-900);
+ }
.capitalize {
text-transform: capitalize;
}
@@ -1783,6 +2233,10 @@
--tw-ease: linear;
transition-timing-function: linear;
}
+ .ease-out {
+ --tw-ease: var(--ease-out);
+ transition-timing-function: var(--ease-out);
+ }
.fade-in-0 {
--tw-enter-opacity: calc(0/100);
--tw-enter-opacity: 0;
@@ -1802,6 +2256,24 @@
.\[--cell-size\:--spacing\(8\)\] {
--cell-size: calc(var(--spacing) * 8);
}
+ .\[appkit\:cache\] {
+ appkit: cache;
+ }
+ .\[appkit\:connector\] {
+ appkit: connector;
+ }
+ .\[appkit\:my-plugin\] {
+ appkit: my-plugin;
+ }
+ .\[appkit\:server\] {
+ appkit: server;
+ }
+ .\[appkit\:test-scope\] {
+ appkit: test-scope;
+ }
+ .\[appkit\:test\] {
+ appkit: test;
+ }
.running {
animation-play-state: running;
}
@@ -2296,6 +2768,13 @@
}
}
}
+ .hover\:bg-blue-100 {
+ &:hover {
+ @media (hover: hover) {
+ background-color: var(--color-blue-100);
+ }
+ }
+ }
.hover\:bg-destructive\/90 {
&:hover {
@media (hover: hover) {
@@ -2306,6 +2785,27 @@
}
}
}
+ .hover\:bg-emerald-100 {
+ &:hover {
+ @media (hover: hover) {
+ background-color: var(--color-emerald-100);
+ }
+ }
+ }
+ .hover\:bg-gray-100 {
+ &:hover {
+ @media (hover: hover) {
+ background-color: var(--color-gray-100);
+ }
+ }
+ }
+ .hover\:bg-green-100 {
+ &:hover {
+ @media (hover: hover) {
+ background-color: var(--color-green-100);
+ }
+ }
+ }
.hover\:bg-muted {
&:hover {
@media (hover: hover) {
@@ -2333,6 +2833,13 @@
}
}
}
+ .hover\:bg-red-100 {
+ &:hover {
+ @media (hover: hover) {
+ background-color: var(--color-red-100);
+ }
+ }
+ }
.hover\:bg-secondary\/80 {
&:hover {
@media (hover: hover) {
@@ -2350,6 +2857,13 @@
}
}
}
+ .hover\:bg-yellow-100 {
+ &:hover {
+ @media (hover: hover) {
+ background-color: var(--color-yellow-100);
+ }
+ }
+ }
.hover\:text-accent-foreground {
&:hover {
@media (hover: hover) {
@@ -2357,6 +2871,27 @@
}
}
}
+ .hover\:text-blue-700 {
+ &:hover {
+ @media (hover: hover) {
+ color: var(--color-blue-700);
+ }
+ }
+ }
+ .hover\:text-blue-800 {
+ &:hover {
+ @media (hover: hover) {
+ color: var(--color-blue-800);
+ }
+ }
+ }
+ .hover\:text-emerald-700 {
+ &:hover {
+ @media (hover: hover) {
+ color: var(--color-emerald-700);
+ }
+ }
+ }
.hover\:text-foreground {
&:hover {
@media (hover: hover) {
@@ -2364,6 +2899,20 @@
}
}
}
+ .hover\:text-gray-700 {
+ &:hover {
+ @media (hover: hover) {
+ color: var(--color-gray-700);
+ }
+ }
+ }
+ .hover\:text-green-700 {
+ &:hover {
+ @media (hover: hover) {
+ color: var(--color-green-700);
+ }
+ }
+ }
.hover\:text-muted-foreground {
&:hover {
@media (hover: hover) {
@@ -2371,6 +2920,20 @@
}
}
}
+ .hover\:text-red-700 {
+ &:hover {
+ @media (hover: hover) {
+ color: var(--color-red-700);
+ }
+ }
+ }
+ .hover\:text-secondary-foreground {
+ &:hover {
+ @media (hover: hover) {
+ color: var(--secondary-foreground);
+ }
+ }
+ }
.hover\:text-sidebar-accent-foreground {
&:hover {
@media (hover: hover) {
@@ -2378,6 +2941,13 @@
}
}
}
+ .hover\:text-yellow-700 {
+ &:hover {
+ @media (hover: hover) {
+ color: var(--color-yellow-700);
+ }
+ }
+ }
.hover\:underline {
&:hover {
@media (hover: hover) {
@@ -2385,6 +2955,13 @@
}
}
}
+ .hover\:opacity-80 {
+ &:hover {
+ @media (hover: hover) {
+ opacity: 80%;
+ }
+ }
+ }
.hover\:opacity-100 {
&:hover {
@media (hover: hover) {
@@ -2400,6 +2977,14 @@
}
}
}
+ .hover\:shadow-lg {
+ &:hover {
+ @media (hover: hover) {
+ --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
+ }
+ }
+ }
.hover\:ring-4 {
&:hover {
@media (hover: hover) {
@@ -2563,6 +3148,12 @@
outline-color: var(--ring);
}
}
+ .focus-visible\:outline-none {
+ &:focus-visible {
+ --tw-outline-style: none;
+ outline-style: none;
+ }
+ }
.active\:bg-sidebar-accent {
&:active {
background-color: var(--sidebar-accent);
@@ -3883,6 +4474,16 @@
position: absolute;
}
}
+ .md\:col-span-2 {
+ @media (width >= 48rem) {
+ grid-column: span 2 / span 2;
+ }
+ }
+ .md\:col-span-3 {
+ @media (width >= 48rem) {
+ grid-column: span 3 / span 3;
+ }
+ }
.md\:block {
@media (width >= 48rem) {
display: block;
@@ -3923,6 +4524,11 @@
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
+ .md\:grid-cols-3 {
+ @media (width >= 48rem) {
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ }
+ }
.md\:flex-row {
@media (width >= 48rem) {
flex-direction: row;
@@ -4010,6 +4616,11 @@
width: 600px;
}
}
+ .lg\:grid-cols-2 {
+ @media (width >= 64rem) {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+ }
.lg\:grid-cols-\[\.75fr_1fr\] {
@media (width >= 64rem) {
grid-template-columns: .75fr 1fr;
@@ -4365,6 +4976,35 @@
width: calc(var(--spacing) * 5);
}
}
+ .\[\&_a\]\:underline {
+ & a {
+ text-decoration-line: underline;
+ }
+ }
+ .\[\&_code\]\:rounded {
+ & code {
+ border-radius: var(--radius);
+ }
+ }
+ .\[\&_code\]\:bg-background\/50 {
+ & code {
+ background-color: var(--background);
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--background) 50%, transparent);
+ }
+ }
+ }
+ .\[\&_code\]\:px-1 {
+ & code {
+ padding-inline: calc(var(--spacing) * 1);
+ }
+ }
+ .\[\&_code\]\:text-xs {
+ & code {
+ font-size: var(--text-xs);
+ line-height: var(--tw-leading, var(--text-xs--line-height));
+ }
+ }
.\[\&_img\]\:size-full {
& img {
width: 100%;
@@ -4376,12 +5016,82 @@
object-fit: cover;
}
}
+ .\[\&_li\]\:my-0 {
+ & li {
+ margin-block: calc(var(--spacing) * 0);
+ }
+ }
+ .\[\&_ol\]\:my-1 {
+ & ol {
+ margin-block: calc(var(--spacing) * 1);
+ }
+ }
+ .\[\&_p\]\:my-1 {
+ & p {
+ margin-block: calc(var(--spacing) * 1);
+ }
+ }
.\[\&_p\]\:leading-relaxed {
& p {
--tw-leading: var(--leading-relaxed);
line-height: var(--leading-relaxed);
}
}
+ .\[\&_pre\]\:m-0 {
+ & pre {
+ margin: calc(var(--spacing) * 0);
+ }
+ }
+ .\[\&_pre\]\:min-h-\[300px\] {
+ & pre {
+ min-height: 300px;
+ }
+ }
+ .\[\&_pre\]\:overflow-x-auto {
+ & pre {
+ overflow-x: auto;
+ }
+ }
+ .\[\&_pre\]\:rounded {
+ & pre {
+ border-radius: var(--radius);
+ }
+ }
+ .\[\&_pre\]\:rounded-md {
+ & pre {
+ border-radius: var(--radius-md);
+ }
+ }
+ .\[\&_pre\]\:bg-background\/50 {
+ & pre {
+ background-color: var(--background);
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--background) 50%, transparent);
+ }
+ }
+ }
+ .\[\&_pre\]\:p-2 {
+ & pre {
+ padding: calc(var(--spacing) * 2);
+ }
+ }
+ .\[\&_pre\]\:p-4 {
+ & pre {
+ padding: calc(var(--spacing) * 4);
+ }
+ }
+ .\[\&_pre\]\:text-sm {
+ & pre {
+ font-size: var(--text-sm);
+ line-height: var(--tw-leading, var(--text-sm--line-height));
+ }
+ }
+ .\[\&_pre\]\:text-xs {
+ & pre {
+ font-size: var(--text-xs);
+ line-height: var(--tw-leading, var(--text-xs--line-height));
+ }
+ }
.\[\&_svg\]\:pointer-events-none {
& svg {
pointer-events: none;
@@ -4415,6 +5125,59 @@
color: var(--muted-foreground);
}
}
+ .\[\&_table\]\:border-collapse {
+ & table {
+ border-collapse: collapse;
+ }
+ }
+ .\[\&_table\]\:text-xs {
+ & table {
+ font-size: var(--text-xs);
+ line-height: var(--tw-leading, var(--text-xs--line-height));
+ }
+ }
+ .\[\&_td\]\:border {
+ & td {
+ border-style: var(--tw-border-style);
+ border-width: 1px;
+ }
+ }
+ .\[\&_td\]\:border-border {
+ & td {
+ border-color: var(--border);
+ }
+ }
+ .\[\&_td\]\:px-2 {
+ & td {
+ padding-inline: calc(var(--spacing) * 2);
+ }
+ }
+ .\[\&_td\]\:py-1 {
+ & td {
+ padding-block: calc(var(--spacing) * 1);
+ }
+ }
+ .\[\&_th\]\:border {
+ & th {
+ border-style: var(--tw-border-style);
+ border-width: 1px;
+ }
+ }
+ .\[\&_th\]\:border-border {
+ & th {
+ border-color: var(--border);
+ }
+ }
+ .\[\&_th\]\:px-2 {
+ & th {
+ padding-inline: calc(var(--spacing) * 2);
+ }
+ }
+ .\[\&_th\]\:py-1 {
+ & th {
+ padding-block: calc(var(--spacing) * 1);
+ }
+ }
.\[\&_tr\]\:border-b {
& tr {
border-bottom-style: var(--tw-border-style);
@@ -4427,6 +5190,11 @@
border-width: 0px;
}
}
+ .\[\&_ul\]\:my-1 {
+ & ul {
+ margin-block: calc(var(--spacing) * 1);
+ }
+ }
.\[\&\+\[data-slot\=item-content\]\]\:flex-none {
&+[data-slot=item-content] {
flex: none;
@@ -4732,6 +5500,22 @@
border-radius: calc(var(--radius) - 5px);
}
}
+ .\[\&\>pre\]\:m-0 {
+ &>pre {
+ margin: calc(var(--spacing) * 0);
+ }
+ }
+ .\[\&\>pre\]\:p-4 {
+ &>pre {
+ padding: calc(var(--spacing) * 4);
+ }
+ }
+ .\[\&\>pre\]\:text-sm {
+ &>pre {
+ font-size: var(--text-sm);
+ line-height: var(--tw-leading, var(--text-sm--line-height));
+ }
+ }
.\[\&\>span\]\:text-xs {
&>span {
font-size: var(--text-xs);
diff --git a/packages/appkit-ui/package.json b/packages/appkit-ui/package.json
index 6438e987..693acdc2 100644
--- a/packages/appkit-ui/package.json
+++ b/packages/appkit-ui/package.json
@@ -81,6 +81,7 @@
"embla-carousel-react": "^8.6.0",
"input-otp": "^1.4.2",
"lucide-react": "^0.554.0",
+ "marked": "^17.0.3",
"next-themes": "^0.4.6",
"react-day-picker": "^9.11.3",
"react-hook-form": "^7.68.0",
diff --git a/packages/appkit-ui/src/react/genie/genie-chat-input.tsx b/packages/appkit-ui/src/react/genie/genie-chat-input.tsx
new file mode 100644
index 00000000..763486e1
--- /dev/null
+++ b/packages/appkit-ui/src/react/genie/genie-chat-input.tsx
@@ -0,0 +1,74 @@
+import { type KeyboardEvent, useRef, useState } from "react";
+import { cn } from "../lib/utils";
+import { Button } from "../ui/button";
+
+export interface GenieChatInputProps {
+ onSend: (content: string) => void;
+ disabled?: boolean;
+ placeholder?: string;
+ className?: string;
+}
+
+export function GenieChatInput({
+ onSend,
+ disabled = false,
+ placeholder = "Ask a question...",
+ className,
+}: GenieChatInputProps) {
+ const [value, setValue] = useState("");
+ const textareaRef = useRef
(null);
+
+ const handleSubmit = () => {
+ const trimmed = value.trim();
+ if (!trimmed || disabled) return;
+ onSend(trimmed);
+ setValue("");
+ if (textareaRef.current) {
+ textareaRef.current.style.height = "auto";
+ }
+ };
+
+ const handleKeyDown = (e: KeyboardEvent) => {
+ if (e.key === "Enter" && !e.shiftKey) {
+ e.preventDefault();
+ handleSubmit();
+ }
+ };
+
+ const handleInput = () => {
+ const textarea = textareaRef.current;
+ if (textarea) {
+ textarea.style.height = "auto";
+ textarea.style.height = `${Math.min(textarea.scrollHeight, 200)}px`;
+ }
+ };
+
+ return (
+
+
+ );
+}
diff --git a/packages/appkit-ui/src/react/genie/genie-chat-message-list.tsx b/packages/appkit-ui/src/react/genie/genie-chat-message-list.tsx
new file mode 100644
index 00000000..024c7362
--- /dev/null
+++ b/packages/appkit-ui/src/react/genie/genie-chat-message-list.tsx
@@ -0,0 +1,84 @@
+import { useEffect, useRef } from "react";
+import { cn } from "../lib/utils";
+import { ScrollArea } from "../ui/scroll-area";
+import { Skeleton } from "../ui/skeleton";
+import { Spinner } from "../ui/spinner";
+import { GenieChatMessage } from "./genie-chat-message";
+import type { GenieChatStatus, GenieMessageItem } from "./types";
+
+export interface GenieChatMessageListProps {
+ messages: GenieMessageItem[];
+ status: GenieChatStatus;
+ className?: string;
+}
+
+const STATUS_LABELS: Record = {
+ ASKING_AI: "Asking AI...",
+ EXECUTING_QUERY: "Executing query...",
+ FILTERING_RESULTS: "Filtering results...",
+ COMPLETED: "Done",
+};
+
+function formatStatus(status: string): string {
+ return STATUS_LABELS[status] ?? status.replace(/_/g, " ").toLowerCase();
+}
+
+function StreamingIndicator({ messages }: { messages: GenieMessageItem[] }) {
+ const last = messages[messages.length - 1];
+ if (last?.role === "assistant" && last.id === "") {
+ return (
+
+
+ {formatStatus(last.status)}
+
+ );
+ }
+ return null;
+}
+
+export function GenieChatMessageList({
+ messages,
+ status,
+ className,
+}: GenieChatMessageListProps) {
+ const scrollRef = useRef(null);
+
+ // Scroll only the ScrollArea viewport, not the page
+ // biome-ignore lint/correctness/useExhaustiveDependencies: intentional triggers for auto-scroll
+ useEffect(() => {
+ const viewport = scrollRef.current?.querySelector(
+ '[data-slot="scroll-area-viewport"]',
+ );
+ if (viewport) {
+ viewport.scrollTop = viewport.scrollHeight;
+ }
+ }, [messages.length, status]);
+
+ return (
+
+
+ {status === "loading-history" && messages.length === 0 && (
+
+
+
+
+
+ )}
+
+ {messages.map((msg) => (
+
+ ))}
+
+ {status === "streaming" && messages.length > 0 && (
+
+ )}
+
+ {messages.length === 0 && status === "idle" && (
+
+ Start a conversation by typing a question below.
+
+ )}
+
+
+ );
+}
diff --git a/packages/appkit-ui/src/react/genie/genie-chat-message.tsx b/packages/appkit-ui/src/react/genie/genie-chat-message.tsx
new file mode 100644
index 00000000..e56b86d2
--- /dev/null
+++ b/packages/appkit-ui/src/react/genie/genie-chat-message.tsx
@@ -0,0 +1,120 @@
+import { marked } from "marked";
+import { useMemo } from "react";
+import { cn } from "../lib/utils";
+import { Avatar, AvatarFallback } from "../ui/avatar";
+import { Card } from "../ui/card";
+import type { GenieAttachmentResponse, GenieMessageItem } from "./types";
+
+/**
+ * Using `marked` instead of `react-markdown` because `react-markdown` depends on
+ * `micromark-util-symbol` which has broken ESM exports with `rolldown-vite`.
+ * Content comes from our own Genie API so `dangerouslySetInnerHTML` is safe.
+ */
+marked.setOptions({ breaks: true, gfm: true });
+
+const markdownStyles = cn(
+ "text-sm",
+ "[&_p]:my-1 [&_ul]:my-1 [&_ol]:my-1 [&_li]:my-0",
+ "[&_pre]:bg-background/50 [&_pre]:p-2 [&_pre]:rounded [&_pre]:text-xs [&_pre]:overflow-x-auto",
+ "[&_code]:text-xs [&_code]:bg-background/50 [&_code]:px-1 [&_code]:rounded",
+ "[&_table]:text-xs [&_th]:px-2 [&_th]:py-1 [&_td]:px-2 [&_td]:py-1",
+ "[&_table]:border-collapse [&_th]:border [&_td]:border",
+ "[&_th]:border-border [&_td]:border-border",
+ "[&_a]:underline",
+);
+
+export interface GenieChatMessageProps {
+ message: GenieMessageItem;
+ className?: string;
+}
+
+function isQueryAttachment(att: GenieAttachmentResponse): boolean {
+ return !!(att.query?.title || att.query?.query);
+}
+
+export function GenieChatMessage({
+ message,
+ className,
+}: GenieChatMessageProps) {
+ const isUser = message.role === "user";
+ const queryAttachments = message.attachments.filter(isQueryAttachment);
+ const html = useMemo(
+ () => (message.content ? (marked.parse(message.content) as string) : ""),
+ [message.content],
+ );
+
+ return (
+
+
+
+ {isUser ? "You" : "AI"}
+
+
+
+
+
+ {html && (
+
+ )}
+
+ {message.error && (
+ {message.error}
+ )}
+
+
+ {queryAttachments.length > 0 && (
+
+ {queryAttachments.map((att) => (
+
+
+
+ {att.query?.title ?? "SQL Query"}
+
+
+ {att.query?.description && (
+
+ {att.query.description}
+
+ )}
+ {att.query?.query && (
+
+ {att.query.query}
+
+ )}
+
+
+
+ ))}
+
+ )}
+
+
+ );
+}
diff --git a/packages/appkit-ui/src/react/genie/genie-chat.tsx b/packages/appkit-ui/src/react/genie/genie-chat.tsx
new file mode 100644
index 00000000..0e4814e3
--- /dev/null
+++ b/packages/appkit-ui/src/react/genie/genie-chat.tsx
@@ -0,0 +1,49 @@
+import { cn } from "../lib/utils";
+import { Button } from "../ui/button";
+import { GenieChatInput } from "./genie-chat-input";
+import { GenieChatMessageList } from "./genie-chat-message-list";
+import type { GenieChatProps } from "./types";
+import { useGenieChat } from "./use-genie-chat";
+
+export function GenieChat({
+ alias,
+ basePath,
+ placeholder,
+ className,
+}: GenieChatProps) {
+ const { messages, status, error, sendMessage, reset } = useGenieChat({
+ alias,
+ basePath,
+ });
+
+ return (
+
+
+
+ {error && (
+
+ {error}
+
+ )}
+
+
+
+ {messages.length > 0 && (
+
+
+
+ )}
+
+ );
+}
diff --git a/packages/appkit-ui/src/react/genie/index.ts b/packages/appkit-ui/src/react/genie/index.ts
new file mode 100644
index 00000000..0055abff
--- /dev/null
+++ b/packages/appkit-ui/src/react/genie/index.ts
@@ -0,0 +1,6 @@
+export { GenieChat } from "./genie-chat";
+export { GenieChatInput } from "./genie-chat-input";
+export { GenieChatMessage } from "./genie-chat-message";
+export { GenieChatMessageList } from "./genie-chat-message-list";
+export type * from "./types";
+export { useGenieChat } from "./use-genie-chat";
diff --git a/packages/appkit-ui/src/react/genie/types.ts b/packages/appkit-ui/src/react/genie/types.ts
new file mode 100644
index 00000000..019bf00f
--- /dev/null
+++ b/packages/appkit-ui/src/react/genie/types.ts
@@ -0,0 +1,90 @@
+/**
+ * Frontend-side Genie types, mirroring backend shapes to avoid
+ * pulling Node.js dependencies into the browser bundle.
+ */
+
+export interface GenieMessageResponse {
+ messageId: string;
+ conversationId: string;
+ spaceId: string;
+ status: string;
+ content: string;
+ attachments?: GenieAttachmentResponse[];
+ error?: string;
+}
+
+export interface GenieAttachmentResponse {
+ attachmentId?: string;
+ query?: {
+ title?: string;
+ description?: string;
+ query?: string;
+ statementId?: string;
+ };
+ text?: { content?: string };
+ suggestedQuestions?: string[];
+}
+
+export type GenieStreamEvent =
+ | {
+ type: "message_start";
+ conversationId: string;
+ messageId: string;
+ spaceId: string;
+ }
+ | { type: "status"; status: string }
+ | { type: "message_result"; message: GenieMessageResponse }
+ | {
+ type: "query_result";
+ attachmentId: string;
+ statementId: string;
+ data: unknown;
+ }
+ | { type: "error"; error: string };
+
+export type GenieChatStatus =
+ | "idle"
+ | "loading-history"
+ | "streaming"
+ | "error";
+
+export interface GenieMessageItem {
+ id: string;
+ role: "user" | "assistant";
+ content: string;
+ status: string;
+ attachments: GenieAttachmentResponse[];
+ queryResults: Map;
+ error?: string;
+}
+
+export interface UseGenieChatOptions {
+ /** Genie space alias (maps to backend route param) */
+ alias: string;
+ /** Base API path. Default: "/api/genie" */
+ basePath?: string;
+ /** Read/write conversationId from URL search params. Default: true */
+ persistInUrl?: boolean;
+ /** URL search param name. Default: "conversationId" */
+ urlParamName?: string;
+}
+
+export interface UseGenieChatReturn {
+ messages: GenieMessageItem[];
+ status: GenieChatStatus;
+ conversationId: string | null;
+ error: string | null;
+ sendMessage: (content: string) => void;
+ reset: () => void;
+}
+
+export interface GenieChatProps {
+ /** Genie space alias */
+ alias: string;
+ /** Base API path. Default: "/api/genie" */
+ basePath?: string;
+ /** Placeholder text for the input. Default: "Ask a question..." */
+ placeholder?: string;
+ /** Custom className for the root container */
+ className?: string;
+}
diff --git a/packages/appkit-ui/src/react/genie/use-genie-chat.ts b/packages/appkit-ui/src/react/genie/use-genie-chat.ts
new file mode 100644
index 00000000..e06df24a
--- /dev/null
+++ b/packages/appkit-ui/src/react/genie/use-genie-chat.ts
@@ -0,0 +1,313 @@
+import { useCallback, useEffect, useRef, useState } from "react";
+import { connectSSE } from "@/js";
+import type {
+ GenieChatStatus,
+ GenieMessageItem,
+ GenieMessageResponse,
+ GenieStreamEvent,
+ UseGenieChatOptions,
+ UseGenieChatReturn,
+} from "./types";
+
+function getUrlParam(name: string): string | null {
+ return new URLSearchParams(window.location.search).get(name);
+}
+
+function setUrlParam(name: string, value: string): void {
+ const url = new URL(window.location.href);
+ url.searchParams.set(name, value);
+ window.history.replaceState({}, "", url.toString());
+}
+
+function removeUrlParam(name: string): void {
+ const url = new URL(window.location.href);
+ url.searchParams.delete(name);
+ window.history.replaceState({}, "", url.toString());
+}
+
+/**
+ * The Genie API puts the user's question in `message.content` and the
+ * actual AI answer in text attachments. Extract the text attachment
+ * content so we display the real answer, not the question echo.
+ */
+function extractAssistantContent(msg: GenieMessageResponse): string {
+ const textParts = (msg.attachments ?? [])
+ .map((att) => att.text?.content)
+ .filter(Boolean) as string[];
+ return textParts.length > 0 ? textParts.join("\n\n") : msg.content;
+}
+
+function makeUserItem(
+ msg: GenieMessageResponse,
+ idSuffix = "",
+): GenieMessageItem {
+ return {
+ id: `${msg.messageId}${idSuffix}`,
+ role: "user",
+ content: msg.content,
+ status: msg.status,
+ attachments: [],
+ queryResults: new Map(),
+ };
+}
+
+function makeAssistantItem(msg: GenieMessageResponse): GenieMessageItem {
+ return {
+ id: msg.messageId,
+ role: "assistant",
+ content: extractAssistantContent(msg),
+ status: msg.status,
+ attachments: msg.attachments ?? [],
+ queryResults: new Map(),
+ error: msg.error,
+ };
+}
+
+/**
+ * The API bundles user question (content) and AI answer (attachments) in one message.
+ * Split into separate user + assistant items for display.
+ */
+function messageResultToItems(msg: GenieMessageResponse): GenieMessageItem[] {
+ const hasAttachments = (msg.attachments?.length ?? 0) > 0;
+ if (!hasAttachments) return [makeUserItem(msg)];
+ return [makeUserItem(msg, "-user"), makeAssistantItem(msg)];
+}
+
+/**
+ * Manages the full Genie chat lifecycle:
+ * SSE streaming, conversation persistence via URL, and history replay.
+ *
+ * @example
+ * ```tsx
+ * const { messages, status, sendMessage, reset } = useGenieChat({ alias: "demo" });
+ * ```
+ */
+export function useGenieChat(options: UseGenieChatOptions): UseGenieChatReturn {
+ const {
+ alias,
+ basePath = "/api/genie",
+ persistInUrl = true,
+ urlParamName = "conversationId",
+ } = options;
+
+ const [messages, setMessages] = useState([]);
+ const [status, setStatus] = useState("idle");
+ const [conversationId, setConversationId] = useState(null);
+ const [error, setError] = useState(null);
+
+ const abortControllerRef = useRef(null);
+ const conversationIdRef = useRef(null);
+
+ useEffect(() => {
+ conversationIdRef.current = conversationId;
+ }, [conversationId]);
+
+ const processEvent = useCallback(
+ (event: GenieStreamEvent, isHistory: boolean) => {
+ switch (event.type) {
+ case "message_start": {
+ setConversationId(event.conversationId);
+ if (persistInUrl) {
+ setUrlParam(urlParamName, event.conversationId);
+ }
+ break;
+ }
+
+ case "status": {
+ setMessages((prev) => {
+ const last = prev[prev.length - 1];
+ if (last?.role === "assistant") {
+ return [...prev.slice(0, -1), { ...last, status: event.status }];
+ }
+ return prev;
+ });
+ break;
+ }
+
+ case "message_result": {
+ const msg = event.message;
+ const hasAttachments = (msg.attachments?.length ?? 0) > 0;
+
+ if (isHistory) {
+ const items = messageResultToItems(msg);
+ setMessages((prev) => [...prev, ...items]);
+ } else if (hasAttachments) {
+ // During streaming we already appended the user message locally,
+ // so only handle assistant results. Messages without attachments
+ // are the user-message echo from the API — skip those.
+ const item = makeAssistantItem(msg);
+ setMessages((prev) => {
+ const last = prev[prev.length - 1];
+ if (last?.role === "assistant" && last.id === "") {
+ return [...prev.slice(0, -1), item];
+ }
+ return [...prev, item];
+ });
+ }
+ break;
+ }
+
+ case "query_result": {
+ setMessages((prev) => {
+ const updated = [...prev];
+ for (let i = updated.length - 1; i >= 0; i--) {
+ const msg = updated[i];
+ if (
+ msg.attachments.some(
+ (a) => a.attachmentId === event.attachmentId,
+ )
+ ) {
+ const queryResults = new Map(msg.queryResults);
+ queryResults.set(event.attachmentId, event.data);
+ updated[i] = { ...msg, queryResults };
+ break;
+ }
+ }
+ return updated;
+ });
+ break;
+ }
+
+ case "error": {
+ setError(event.error);
+ setStatus("error");
+ break;
+ }
+ }
+ },
+ [persistInUrl, urlParamName],
+ );
+
+ const sendMessage = useCallback(
+ (content: string) => {
+ const trimmed = content.trim();
+ if (!trimmed) return;
+
+ abortControllerRef.current?.abort();
+ setError(null);
+ setStatus("streaming");
+
+ const userMessage: GenieMessageItem = {
+ id: crypto.randomUUID(),
+ role: "user",
+ content: trimmed,
+ status: "COMPLETED",
+ attachments: [],
+ queryResults: new Map(),
+ };
+
+ const assistantPlaceholder: GenieMessageItem = {
+ id: "",
+ role: "assistant",
+ content: "",
+ status: "ASKING_AI",
+ attachments: [],
+ queryResults: new Map(),
+ };
+
+ setMessages((prev) => [...prev, userMessage, assistantPlaceholder]);
+
+ const abortController = new AbortController();
+ abortControllerRef.current = abortController;
+
+ connectSSE({
+ url: `${basePath}/${encodeURIComponent(alias)}/messages`,
+ payload: {
+ content: trimmed,
+ conversationId: conversationIdRef.current ?? undefined,
+ },
+ signal: abortController.signal,
+ onMessage: async (message) => {
+ try {
+ processEvent(JSON.parse(message.data) as GenieStreamEvent, false);
+ } catch {
+ // Malformed SSE data
+ }
+ },
+ onError: (err) => {
+ if (abortController.signal.aborted) return;
+ setError(
+ err instanceof Error
+ ? err.message
+ : "Connection error. Please try again.",
+ );
+ setStatus("error");
+ setMessages((prev) => {
+ const last = prev[prev.length - 1];
+ return last?.role === "assistant" && last.id === ""
+ ? prev.slice(0, -1)
+ : prev;
+ });
+ },
+ }).then(() => {
+ if (!abortController.signal.aborted) {
+ setStatus((prev) => (prev === "error" ? "error" : "idle"));
+ }
+ });
+ },
+ [alias, basePath, processEvent],
+ );
+
+ const loadHistory = useCallback(
+ (convId: string) => {
+ abortControllerRef.current?.abort();
+ setStatus("loading-history");
+ setError(null);
+ setMessages([]);
+ setConversationId(convId);
+
+ const abortController = new AbortController();
+ abortControllerRef.current = abortController;
+
+ connectSSE({
+ url: `${basePath}/${encodeURIComponent(alias)}/conversations/${encodeURIComponent(convId)}`,
+ signal: abortController.signal,
+ onMessage: async (message) => {
+ try {
+ processEvent(JSON.parse(message.data) as GenieStreamEvent, true);
+ } catch {
+ // Malformed SSE data
+ }
+ },
+ onError: (err) => {
+ if (abortController.signal.aborted) return;
+ setError(
+ err instanceof Error
+ ? err.message
+ : "Failed to load conversation history.",
+ );
+ setStatus("error");
+ },
+ }).then(() => {
+ if (!abortController.signal.aborted) {
+ setStatus((prev) => (prev === "error" ? "error" : "idle"));
+ }
+ });
+ },
+ [alias, basePath, processEvent],
+ );
+
+ const reset = useCallback(() => {
+ abortControllerRef.current?.abort();
+ setMessages([]);
+ setConversationId(null);
+ setError(null);
+ setStatus("idle");
+ if (persistInUrl) {
+ removeUrlParam(urlParamName);
+ }
+ }, [persistInUrl, urlParamName]);
+
+ useEffect(() => {
+ if (!persistInUrl) return;
+ const existingId = getUrlParam(urlParamName);
+ if (existingId) {
+ loadHistory(existingId);
+ }
+ return () => {
+ abortControllerRef.current?.abort();
+ };
+ }, [persistInUrl, urlParamName, loadHistory]);
+
+ return { messages, status, conversationId, error, sendMessage, reset };
+}
diff --git a/packages/appkit-ui/src/react/index.ts b/packages/appkit-ui/src/react/index.ts
index 9da3c092..dc52a2f3 100644
--- a/packages/appkit-ui/src/react/index.ts
+++ b/packages/appkit-ui/src/react/index.ts
@@ -1,4 +1,5 @@
export * from "./charts";
+export * from "./genie";
export * from "./hooks";
export * from "./lib/utils";
export * from "./portal-container-context";
diff --git a/packages/appkit/src/plugins/genie/genie.ts b/packages/appkit/src/plugins/genie/genie.ts
index 0d958861..31690db5 100644
--- a/packages/appkit/src/plugins/genie/genie.ts
+++ b/packages/appkit/src/plugins/genie/genie.ts
@@ -315,7 +315,8 @@ export class GeniePlugin extends Plugin {
pageToken = response.next_page_token;
} while (pageToken && allMessages.length < maxMessages);
- return allMessages.slice(0, maxMessages);
+ // Genie API returns newest-first; reverse to chronological order
+ return allMessages.slice(0, maxMessages).reverse();
}
async _handleGetConversation(
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 4b598b89..610d666a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -444,6 +444,9 @@ importers:
lucide-react:
specifier: ^0.554.0
version: 0.554.0(react@19.2.0)
+ marked:
+ specifier: ^17.0.3
+ version: 17.0.3
next-themes:
specifier: ^0.4.6
version: 0.4.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
@@ -3028,8 +3031,8 @@ packages:
resolution: {integrity: sha512-Z7x2dZOmznihvdvCvLKMl+nswtOSVxS2H2ocar+U9xx6iMfTp0VGIrX6a4xB1v80IwOPC7dT1LXIJrY70Xu3Jw==}
engines: {node: ^20.19.0 || >=22.12.0}
- '@oxc-project/types@0.113.0':
- resolution: {integrity: sha512-Tp3XmgxwNQ9pEN9vxgJBAqdRamHibi76iowQ38O2I4PMpcvNRQNVsU2n1x1nv9yh0XoTrGFzf7cZSGxmixxrhA==}
+ '@oxc-project/types@0.114.0':
+ resolution: {integrity: sha512-//nBfbzHQHvJs8oFIjv6coZ6uxQ4alLfiPe6D5vit6c4pmxATHHlVwgB1k+Hv4yoAMyncdxgRBF5K4BYWUCzvA==}
'@oxc-project/types@0.93.0':
resolution: {integrity: sha512-yNtwmWZIBtJsMr5TEfoZFDxIWV6OdScOpza/f5YxbqUMJk+j6QX3Cf3jgZShGEFYWQJ5j9mJ6jM0tZHu2J9Yrg==}
@@ -3754,8 +3757,8 @@ packages:
cpu: [arm64]
os: [android]
- '@rolldown/binding-android-arm64@1.0.0-rc.4':
- resolution: {integrity: sha512-vRq9f4NzvbdZavhQbjkJBx7rRebDKYR9zHfO/Wg486+I7bSecdUapzCm5cyXoK+LHokTxgSq7A5baAXUZkIz0w==}
+ '@rolldown/binding-android-arm64@1.0.0-rc.5':
+ resolution: {integrity: sha512-zCEmUrt1bggwgBgeKLxNj217J1OrChrp3jJt24VK9jAharSTeVaHODNL+LpcQVhRz+FktYWfT9cjo5oZ99ZLpg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [android]
@@ -3766,8 +3769,8 @@ packages:
cpu: [arm64]
os: [darwin]
- '@rolldown/binding-darwin-arm64@1.0.0-rc.4':
- resolution: {integrity: sha512-kFgEvkWLqt3YCgKB5re9RlIrx9bRsvyVUnaTakEpOPuLGzLpLapYxE9BufJNvPg8GjT6mB1alN4yN1NjzoeM8Q==}
+ '@rolldown/binding-darwin-arm64@1.0.0-rc.5':
+ resolution: {integrity: sha512-ZP9xb9lPAex36pvkNWCjSEJW/Gfdm9I3ssiqOFLmpZ/vosPXgpoGxCmh+dX1Qs+/bWQE6toNFXWWL8vYoKoK9Q==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [darwin]
@@ -3778,8 +3781,8 @@ packages:
cpu: [x64]
os: [darwin]
- '@rolldown/binding-darwin-x64@1.0.0-rc.4':
- resolution: {integrity: sha512-JXmaOJGsL/+rsmMfutcDjxWM2fTaVgCHGoXS7nE8Z3c9NAYjGqHvXrAhMUZvMpHS/k7Mg+X7n/MVKb7NYWKKww==}
+ '@rolldown/binding-darwin-x64@1.0.0-rc.5':
+ resolution: {integrity: sha512-7IdrPunf6dp9mywMgTOKMMGDnMHQ6+h5gRl6LW8rhD8WK2kXX0IwzcM5Zc0B5J7xQs8QWOlKjv8BJsU/1CD3pg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [darwin]
@@ -3790,8 +3793,8 @@ packages:
cpu: [x64]
os: [freebsd]
- '@rolldown/binding-freebsd-x64@1.0.0-rc.4':
- resolution: {integrity: sha512-ep3Catd6sPnHTM0P4hNEvIv5arnDvk01PfyJIJ+J3wVCG1eEaPo09tvFqdtcaTrkwQy0VWR24uz+cb4IsK53Qw==}
+ '@rolldown/binding-freebsd-x64@1.0.0-rc.5':
+ resolution: {integrity: sha512-o/JCk+dL0IN68EBhZ4DqfsfvxPfMeoM6cJtxORC1YYoxGHZyth2Kb2maXDb4oddw2wu8iIbnYXYPEzBtAF5CAg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [freebsd]
@@ -3802,8 +3805,8 @@ packages:
cpu: [arm]
os: [linux]
- '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.4':
- resolution: {integrity: sha512-LwA5ayKIpnsgXJEwWc3h8wPiS33NMIHd9BhsV92T8VetVAbGe2qXlJwNVDGHN5cOQ22R9uYvbrQir2AB+ntT2w==}
+ '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.5':
+ resolution: {integrity: sha512-IIBwTtA6VwxQLcEgq2mfrUgam7VvPZjhd/jxmeS1npM+edWsrrpRLHUdze+sk4rhb8/xpP3flemgcZXXUW6ukw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm]
os: [linux]
@@ -3814,8 +3817,8 @@ packages:
cpu: [arm64]
os: [linux]
- '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.4':
- resolution: {integrity: sha512-AC1WsGdlV1MtGay/OQ4J9T7GRadVnpYRzTcygV1hKnypbYN20Yh4t6O1Sa2qRBMqv1etulUknqXjc3CTIsBu6A==}
+ '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.5':
+ resolution: {integrity: sha512-KSol1De1spMZL+Xg7K5IBWXIvRWv7+pveaxFWXpezezAG7CS6ojzRjtCGCiLxQricutTAi/LkNWKMsd2wNhMKQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
@@ -3826,8 +3829,8 @@ packages:
cpu: [arm64]
os: [linux]
- '@rolldown/binding-linux-arm64-musl@1.0.0-rc.4':
- resolution: {integrity: sha512-lU+6rgXXViO61B4EudxtVMXSOfiZONR29Sys5VGSetUY7X8mg9FCKIIjcPPj8xNDeYzKl+H8F/qSKOBVFJChCQ==}
+ '@rolldown/binding-linux-arm64-musl@1.0.0-rc.5':
+ resolution: {integrity: sha512-WFljyDkxtXRlWxMjxeegf7xMYXxUr8u7JdXlOEWKYgDqEgxUnSEsVDxBiNWQ1D5kQKwf8Wo4sVKEYPRhCdsjwA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
@@ -3838,8 +3841,8 @@ packages:
cpu: [x64]
os: [linux]
- '@rolldown/binding-linux-x64-gnu@1.0.0-rc.4':
- resolution: {integrity: sha512-DZaN1f0PGp/bSvKhtw50pPsnln4T13ycDq1FrDWRiHmWt1JeW+UtYg9touPFf8yt993p8tS2QjybpzKNTxYEwg==}
+ '@rolldown/binding-linux-x64-gnu@1.0.0-rc.5':
+ resolution: {integrity: sha512-CUlplTujmbDWp2gamvrqVKi2Or8lmngXT1WxsizJfts7JrvfGhZObciaY/+CbdbS9qNnskvwMZNEhTPrn7b+WA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
@@ -3850,8 +3853,8 @@ packages:
cpu: [x64]
os: [linux]
- '@rolldown/binding-linux-x64-musl@1.0.0-rc.4':
- resolution: {integrity: sha512-RnGxwZLN7fhMMAItnD6dZ7lvy+TI7ba+2V54UF4dhaWa/p8I/ys1E73KO6HmPmgz92ZkfD8TXS1IMV8+uhbR9g==}
+ '@rolldown/binding-linux-x64-musl@1.0.0-rc.5':
+ resolution: {integrity: sha512-wdf7g9NbVZCeAo2iGhsjJb7I8ZFfs6X8bumfrWg82VK+8P6AlLXwk48a1ASiJQDTS7Svq2xVzZg3sGO2aXpHRA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
@@ -3862,8 +3865,8 @@ packages:
cpu: [arm64]
os: [openharmony]
- '@rolldown/binding-openharmony-arm64@1.0.0-rc.4':
- resolution: {integrity: sha512-6lcI79+X8klGiGd8yHuTgQRjuuJYNggmEml+RsyN596P23l/zf9FVmJ7K0KVKkFAeYEdg0iMUKyIxiV5vebDNQ==}
+ '@rolldown/binding-openharmony-arm64@1.0.0-rc.5':
+ resolution: {integrity: sha512-0CWY7ubu12nhzz+tkpHjoG3IRSTlWYe0wrfJRf4qqjqQSGtAYgoL9kwzdvlhaFdZ5ffVeyYw9qLsChcjUMEloQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [openharmony]
@@ -3873,8 +3876,8 @@ packages:
engines: {node: '>=14.0.0'}
cpu: [wasm32]
- '@rolldown/binding-wasm32-wasi@1.0.0-rc.4':
- resolution: {integrity: sha512-wz7ohsKCAIWy91blZ/1FlpPdqrsm1xpcEOQVveWoL6+aSPKL4VUcoYmmzuLTssyZxRpEwzuIxL/GDsvpjaBtOw==}
+ '@rolldown/binding-wasm32-wasi@1.0.0-rc.5':
+ resolution: {integrity: sha512-LztXnGzv6t2u830mnZrFLRVqT/DPJ9DL4ZTz/y93rqUVkeHjMMYIYaFj+BUthiYxbVH9dH0SZYufETspKY/NhA==}
engines: {node: '>=14.0.0'}
cpu: [wasm32]
@@ -3884,8 +3887,8 @@ packages:
cpu: [arm64]
os: [win32]
- '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.4':
- resolution: {integrity: sha512-cfiMrfuWCIgsFmcVG0IPuO6qTRHvF7NuG3wngX1RZzc6dU8FuBFb+J3MIR5WrdTNozlumfgL4cvz+R4ozBCvsQ==}
+ '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.5':
+ resolution: {integrity: sha512-jUct1XVeGtyjqJXEAfvdFa8xoigYZ2rge7nYEm70ppQxpfH9ze2fbIrpHmP2tNM2vL/F6Dd0CpXhpjPbC6bSxQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [win32]
@@ -3902,8 +3905,8 @@ packages:
cpu: [x64]
os: [win32]
- '@rolldown/binding-win32-x64-msvc@1.0.0-rc.4':
- resolution: {integrity: sha512-p6UeR9y7ht82AH57qwGuFYn69S6CZ7LLKdCKy/8T3zS9VTrJei2/CGsTUV45Da4Z9Rbhc7G4gyWQ/Ioamqn09g==}
+ '@rolldown/binding-win32-x64-msvc@1.0.0-rc.5':
+ resolution: {integrity: sha512-VQ8F9ld5gw29epjnVGdrx8ugiLTe8BMqmhDYy7nGbdeDo4HAt4bgdZvLbViEhg7DZyHLpiEUlO5/jPSUrIuxRQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [win32]
@@ -3917,8 +3920,8 @@ packages:
'@rolldown/pluginutils@1.0.0-beta.47':
resolution: {integrity: sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw==}
- '@rolldown/pluginutils@1.0.0-rc.4':
- resolution: {integrity: sha512-1BrrmTu0TWfOP1riA8uakjFc9bpIUGzVKETsOtzY39pPga8zELGDl8eu1Dx7/gjM5CAz14UknsUMpBO8L+YntQ==}
+ '@rolldown/pluginutils@1.0.0-rc.5':
+ resolution: {integrity: sha512-RxlLX/DPoarZ9PtxVrQgZhPoor987YtKQqCo5zkjX+0S0yLJ7Vv515Wk6+xtTL67VONKJKxETWZwuZjss2idYw==}
'@rollup/rollup-android-arm-eabi@4.52.4':
resolution: {integrity: sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==}
@@ -8007,6 +8010,11 @@ packages:
engines: {node: '>= 20'}
hasBin: true
+ marked@17.0.3:
+ resolution: {integrity: sha512-jt1v2ObpyOKR8p4XaUJVk3YWRJ5n+i4+rjQopxvV32rSndTJXvIzuUdWWIy/1pFQMkQmvTXawzDNqOH/CUmx6A==}
+ engines: {node: '>= 20'}
+ hasBin: true
+
math-intrinsics@1.1.0:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
@@ -9764,8 +9772,8 @@ packages:
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
- rolldown@1.0.0-rc.4:
- resolution: {integrity: sha512-V2tPDUrY3WSevrvU2E41ijZlpF+5PbZu4giH+VpNraaadsJGHa4fR6IFwsocVwEXDoAdIv5qgPPxgrvKAOIPtA==}
+ rolldown@1.0.0-rc.5:
+ resolution: {integrity: sha512-0AdalTs6hNTioaCYIkAa7+xsmHBfU5hCNclZnM/lp7lGGDuUOb6N4BVNtwiomybbencDjq/waKjTImqiGCs5sw==}
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
@@ -14721,7 +14729,7 @@ snapshots:
'@oxc-project/runtime@0.92.0': {}
- '@oxc-project/types@0.113.0': {}
+ '@oxc-project/types@0.114.0': {}
'@oxc-project/types@0.93.0': {}
@@ -15469,61 +15477,61 @@ snapshots:
'@rolldown/binding-android-arm64@1.0.0-beta.41':
optional: true
- '@rolldown/binding-android-arm64@1.0.0-rc.4':
+ '@rolldown/binding-android-arm64@1.0.0-rc.5':
optional: true
'@rolldown/binding-darwin-arm64@1.0.0-beta.41':
optional: true
- '@rolldown/binding-darwin-arm64@1.0.0-rc.4':
+ '@rolldown/binding-darwin-arm64@1.0.0-rc.5':
optional: true
'@rolldown/binding-darwin-x64@1.0.0-beta.41':
optional: true
- '@rolldown/binding-darwin-x64@1.0.0-rc.4':
+ '@rolldown/binding-darwin-x64@1.0.0-rc.5':
optional: true
'@rolldown/binding-freebsd-x64@1.0.0-beta.41':
optional: true
- '@rolldown/binding-freebsd-x64@1.0.0-rc.4':
+ '@rolldown/binding-freebsd-x64@1.0.0-rc.5':
optional: true
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.41':
optional: true
- '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.4':
+ '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.5':
optional: true
'@rolldown/binding-linux-arm64-gnu@1.0.0-beta.41':
optional: true
- '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.4':
+ '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.5':
optional: true
'@rolldown/binding-linux-arm64-musl@1.0.0-beta.41':
optional: true
- '@rolldown/binding-linux-arm64-musl@1.0.0-rc.4':
+ '@rolldown/binding-linux-arm64-musl@1.0.0-rc.5':
optional: true
'@rolldown/binding-linux-x64-gnu@1.0.0-beta.41':
optional: true
- '@rolldown/binding-linux-x64-gnu@1.0.0-rc.4':
+ '@rolldown/binding-linux-x64-gnu@1.0.0-rc.5':
optional: true
'@rolldown/binding-linux-x64-musl@1.0.0-beta.41':
optional: true
- '@rolldown/binding-linux-x64-musl@1.0.0-rc.4':
+ '@rolldown/binding-linux-x64-musl@1.0.0-rc.5':
optional: true
'@rolldown/binding-openharmony-arm64@1.0.0-beta.41':
optional: true
- '@rolldown/binding-openharmony-arm64@1.0.0-rc.4':
+ '@rolldown/binding-openharmony-arm64@1.0.0-rc.5':
optional: true
'@rolldown/binding-wasm32-wasi@1.0.0-beta.41':
@@ -15531,7 +15539,7 @@ snapshots:
'@napi-rs/wasm-runtime': 1.0.7
optional: true
- '@rolldown/binding-wasm32-wasi@1.0.0-rc.4':
+ '@rolldown/binding-wasm32-wasi@1.0.0-rc.5':
dependencies:
'@napi-rs/wasm-runtime': 1.1.1
optional: true
@@ -15539,7 +15547,7 @@ snapshots:
'@rolldown/binding-win32-arm64-msvc@1.0.0-beta.41':
optional: true
- '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.4':
+ '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.5':
optional: true
'@rolldown/binding-win32-ia32-msvc@1.0.0-beta.41':
@@ -15548,7 +15556,7 @@ snapshots:
'@rolldown/binding-win32-x64-msvc@1.0.0-beta.41':
optional: true
- '@rolldown/binding-win32-x64-msvc@1.0.0-rc.4':
+ '@rolldown/binding-win32-x64-msvc@1.0.0-rc.5':
optional: true
'@rolldown/pluginutils@1.0.0-beta.38': {}
@@ -15557,7 +15565,7 @@ snapshots:
'@rolldown/pluginutils@1.0.0-beta.47': {}
- '@rolldown/pluginutils@1.0.0-rc.4': {}
+ '@rolldown/pluginutils@1.0.0-rc.5': {}
'@rollup/rollup-android-arm-eabi@4.52.4':
optional: true
@@ -20160,6 +20168,8 @@ snapshots:
marked@16.4.2: {}
+ marked@17.0.3: {}
+
math-intrinsics@1.1.0: {}
mdast-util-directive@3.1.0:
@@ -22342,7 +22352,7 @@ snapshots:
robust-predicates@3.0.2: {}
- rolldown-plugin-dts@0.16.11(rolldown@1.0.0-rc.4)(typescript@5.9.3):
+ rolldown-plugin-dts@0.16.11(rolldown@1.0.0-rc.5)(typescript@5.9.3):
dependencies:
'@babel/generator': 7.28.3
'@babel/parser': 7.28.5
@@ -22353,7 +22363,7 @@ snapshots:
dts-resolver: 2.1.2
get-tsconfig: 4.12.0
magic-string: 0.30.19
- rolldown: 1.0.0-rc.4
+ rolldown: 1.0.0-rc.5
optionalDependencies:
typescript: 5.9.3
transitivePeerDependencies:
@@ -22417,24 +22427,24 @@ snapshots:
'@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.41
'@rolldown/binding-win32-x64-msvc': 1.0.0-beta.41
- rolldown@1.0.0-rc.4:
+ rolldown@1.0.0-rc.5:
dependencies:
- '@oxc-project/types': 0.113.0
- '@rolldown/pluginutils': 1.0.0-rc.4
+ '@oxc-project/types': 0.114.0
+ '@rolldown/pluginutils': 1.0.0-rc.5
optionalDependencies:
- '@rolldown/binding-android-arm64': 1.0.0-rc.4
- '@rolldown/binding-darwin-arm64': 1.0.0-rc.4
- '@rolldown/binding-darwin-x64': 1.0.0-rc.4
- '@rolldown/binding-freebsd-x64': 1.0.0-rc.4
- '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.4
- '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.4
- '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.4
- '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.4
- '@rolldown/binding-linux-x64-musl': 1.0.0-rc.4
- '@rolldown/binding-openharmony-arm64': 1.0.0-rc.4
- '@rolldown/binding-wasm32-wasi': 1.0.0-rc.4
- '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.4
- '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.4
+ '@rolldown/binding-android-arm64': 1.0.0-rc.5
+ '@rolldown/binding-darwin-arm64': 1.0.0-rc.5
+ '@rolldown/binding-darwin-x64': 1.0.0-rc.5
+ '@rolldown/binding-freebsd-x64': 1.0.0-rc.5
+ '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.5
+ '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.5
+ '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.5
+ '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.5
+ '@rolldown/binding-linux-x64-musl': 1.0.0-rc.5
+ '@rolldown/binding-openharmony-arm64': 1.0.0-rc.5
+ '@rolldown/binding-wasm32-wasi': 1.0.0-rc.5
+ '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.5
+ '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.5
rollup@4.52.4:
dependencies:
@@ -23084,8 +23094,8 @@ snapshots:
diff: 8.0.2
empathic: 2.0.0
hookable: 5.5.3
- rolldown: 1.0.0-rc.4
- rolldown-plugin-dts: 0.16.11(rolldown@1.0.0-rc.4)(typescript@5.9.3)
+ rolldown: 1.0.0-rc.5
+ rolldown-plugin-dts: 0.16.11(rolldown@1.0.0-rc.5)(typescript@5.9.3)
semver: 7.7.3
tinyexec: 1.0.1
tinyglobby: 0.2.15