👌 IMPROVE: working nextjs using stream-json

This commit is contained in:
kumarabhirup 2026-02-08 18:02:25 -08:00
parent 3568fa09ff
commit 5da09483f8
No known key found for this signature in database
GPG Key ID: DB7CA2289CAB0167
6 changed files with 1167 additions and 112 deletions

View File

@ -1,31 +1,12 @@
import { createUIMessageStream, type UIMessage } from "ai";
import { spawn } from "node:child_process";
import { resolve } from "node:path";
import { createInterface } from "node:readline";
import type { UIMessage } from "ai";
import { runAgent } from "@/lib/agent-runner";
// Force Node.js runtime (required for child_process)
export const runtime = "nodejs";
// Allow streaming responses up to 10 minutes
export const maxDuration = 600;
/** Resolve the repo root (two levels up from apps/web/) */
function repoRoot(): string {
return resolve(process.cwd(), "..", "..");
}
type NdjsonEvent = {
event: string;
runId?: string;
stream?: string;
data?: Record<string, unknown>;
seq?: number;
ts?: number;
sessionKey?: string;
status?: string;
result?: {
payloads?: Array<{ text?: string; mediaUrl?: string | null }>;
meta?: Record<string, unknown>;
};
};
export async function POST(req: Request) {
const { messages }: { messages: UIMessage[] } = await req.json();
@ -37,112 +18,88 @@ export async function POST(req: Request) {
.map((p) => p.text)
.join("\n") ?? "";
console.log("[chat] Received message:", userText);
if (!userText.trim()) {
return new Response("No message provided", { status: 400 });
}
const root = repoRoot();
const scriptPath = resolve(root, "scripts", "run-node.mjs");
const stream = createUIMessageStream({
async execute({ writer }) {
// Create a custom SSE stream
const encoder = new TextEncoder();
const stream = new ReadableStream({
async start(controller) {
const textPartId = `text-${Date.now()}`;
let started = false;
await new Promise<void>((resolvePromise, rejectPromise) => {
const child = spawn(
"node",
[scriptPath, "agent", "--agent", "main", "--message", userText, "--stream-json"],
{
cwd: root,
env: { ...process.env },
stdio: ["ignore", "pipe", "pipe"],
const writeEvent = (data: unknown) => {
const json = JSON.stringify(data);
console.log("[chat] SSE write:", json);
controller.enqueue(encoder.encode(`data: ${json}\n\n`));
};
console.log("[chat] Starting agent stream...");
try {
await runAgent(userText, {
onTextDelta: (delta) => {
console.log("[chat] Text delta:", delta);
if (!started) {
console.log("[chat] Writing text-start");
writeEvent({ type: "text-start", id: textPartId });
started = true;
}
writeEvent({ type: "text-delta", id: textPartId, delta });
},
);
const rl = createInterface({ input: child.stdout });
rl.on("line", (line: string) => {
if (!line.trim()) return;
let event: NdjsonEvent;
try {
event = JSON.parse(line) as NdjsonEvent;
} catch {
return; // skip non-JSON lines (e.g. banner)
}
// Handle assistant text deltas
if (event.event === "agent" && event.stream === "assistant") {
const delta =
typeof event.data?.delta === "string" ? event.data.delta : undefined;
if (delta) {
if (!started) {
writer.write({ type: "text-start", id: textPartId });
started = true;
}
writer.write({ type: "text-delta", id: textPartId, delta });
}
}
// Handle lifecycle end
if (
event.event === "agent" &&
event.stream === "lifecycle" &&
event.data?.phase === "end"
) {
onLifecycleEnd: () => {
console.log("[chat] Lifecycle end, started:", started);
if (started) {
writer.write({ type: "text-end", id: textPartId });
writeEvent({ type: "text-end", id: textPartId });
}
}
},
onError: (err) => {
console.error("[chat] Agent error:", err);
if (!started) {
writeEvent({ type: "text-start", id: textPartId });
writeEvent({
type: "text-delta",
id: textPartId,
delta: `Error starting agent: ${err.message}`,
});
writeEvent({ type: "text-end", id: textPartId });
}
},
onClose: (code) => {
console.log("[chat] Agent closed with code:", code, "started:", started);
// If we never started text, emit an empty response
if (!started) {
writeEvent({ type: "text-start", id: textPartId });
writeEvent({
type: "text-delta",
id: textPartId,
delta: "(No response from agent)",
});
writeEvent({ type: "text-end", id: textPartId });
}
},
});
child.on("close", (code) => {
// If we never started text, emit an empty response
if (!started) {
writer.write({ type: "text-start", id: textPartId });
writer.write({
type: "text-delta",
id: textPartId,
delta: "(No response from agent)",
});
writer.write({ type: "text-end", id: textPartId });
}
if (code !== 0 && code !== null) {
// Non-zero exit but we already streamed what we could
}
resolvePromise();
console.log("[chat] Agent stream complete");
} catch (error) {
console.error("[chat] Stream error:", error);
writeEvent({
type: "error",
error: error instanceof Error ? error.message : String(error),
});
child.on("error", (err) => {
if (!started) {
writer.write({ type: "text-start", id: textPartId });
writer.write({
type: "text-delta",
id: textPartId,
delta: `Error starting agent: ${err.message}`,
});
writer.write({ type: "text-end", id: textPartId });
}
resolvePromise();
});
// Log stderr for debugging
child.stderr?.on("data", (chunk: Buffer) => {
console.error("[openclaw stderr]", chunk.toString());
});
});
},
onError: (error) => {
const message = error instanceof Error ? error.message : String(error);
return `Agent error: ${message}`;
} finally {
controller.close();
}
},
});
return new Response(stream, {
headers: {
"Content-Type": "text/event-stream; charset=utf-8",
"Cache-Control": "no-cache",
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache, no-transform",
Connection: "keep-alive",
},
});

View File

@ -0,0 +1,100 @@
import { spawn } from "node:child_process";
import { createInterface } from "node:readline";
import { join } from "node:path";
export type AgentEvent = {
event: string;
runId?: string;
stream?: string;
data?: Record<string, unknown>;
seq?: number;
ts?: number;
sessionKey?: string;
status?: string;
result?: {
payloads?: Array<{ text?: string; mediaUrl?: string | null }>;
meta?: Record<string, unknown>;
};
};
export type AgentCallback = {
onTextDelta: (delta: string) => void;
onLifecycleEnd: () => void;
onError: (error: Error) => void;
onClose: (code: number | null) => void;
};
/**
* Spawn the openclaw agent and stream its output
*/
export async function runAgent(message: string, callback: AgentCallback): Promise<void> {
// Get repo root - construct path dynamically at runtime
const cwd = process.cwd();
const root = cwd.endsWith(join("apps", "web")) ? join(cwd, "..", "..") : cwd;
// Construct script path at runtime to avoid static analysis
const pathParts = ["scripts", "run-node.mjs"];
const scriptPath = join(root, ...pathParts);
return new Promise<void>((resolve, reject) => {
const child = spawn(
"node",
[scriptPath, "agent", "--agent", "main", "--message", message, "--stream-json"],
{
cwd: root,
env: { ...process.env },
stdio: ["ignore", "pipe", "pipe"],
},
);
const rl = createInterface({ input: child.stdout });
rl.on("line", (line: string) => {
if (!line.trim()) return;
let event: AgentEvent;
try {
event = JSON.parse(line) as AgentEvent;
} catch (err) {
console.log("[agent-runner] Non-JSON line:", line);
return; // skip non-JSON lines
}
console.log("[agent-runner] Event:", event.event, event.stream, event.data);
// Handle assistant text deltas
if (event.event === "agent" && event.stream === "assistant") {
const delta = typeof event.data?.delta === "string" ? event.data.delta : undefined;
if (delta) {
console.log("[agent-runner] Delta:", delta);
callback.onTextDelta(delta);
}
}
// Handle lifecycle end
if (
event.event === "agent" &&
event.stream === "lifecycle" &&
event.data?.phase === "end"
) {
console.log("[agent-runner] Lifecycle end");
callback.onLifecycleEnd();
}
});
child.on("close", (code) => {
callback.onClose(code);
resolve();
});
child.on("error", (err) => {
callback.onError(err);
resolve();
});
// Log stderr for debugging
child.stderr?.on("data", (chunk: Buffer) => {
console.error("[openclaw stderr]", chunk.toString());
});
});
}

View File

@ -3,6 +3,28 @@ import type { NextConfig } from "next";
const nextConfig: NextConfig = {
// Allow long-running API routes for agent streaming
serverExternalPackages: [],
// Turbopack experimental configuration
experimental: {
turbo: {
resolveAlias: {},
resolveExtensions: [".ts", ".tsx", ".js", ".jsx", ".json"],
},
},
// Ensure Node.js built-ins work correctly (for webpack fallback)
webpack: (config, { isServer }) => {
if (isServer) {
// Don't attempt to bundle Node.js built-ins
config.externals = config.externals || [];
config.externals.push({
"node:child_process": "commonjs node:child_process",
"node:path": "commonjs node:path",
"node:readline": "commonjs node:readline",
});
}
return config;
},
};
export default nextConfig;

534
apps/web/package-lock.json generated Normal file
View File

@ -0,0 +1,534 @@
{
"name": "openclaw-web",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "openclaw-web",
"version": "0.1.0",
"dependencies": {
"@ai-sdk/react": "^3.0.75",
"ai": "^6.0.73",
"next": "^15.3.3",
"react": "^19.1.0",
"react-dom": "^19.1.0"
},
"devDependencies": {
"@tailwindcss/postcss": "^4.1.8",
"@types/node": "^22.15.21",
"@types/react": "^19.1.4",
"@types/react-dom": "^19.1.5",
"tailwindcss": "^4.1.8",
"typescript": "^5.8.3"
}
},
"../../node_modules/.pnpm/@ai-sdk+react@3.0.75_react@19.1.0_zod@4.3.6/node_modules/@ai-sdk/react": {
"version": "3.0.75",
"license": "Apache-2.0",
"dependencies": {
"@ai-sdk/provider-utils": "4.0.13",
"ai": "6.0.73",
"swr": "^2.2.5",
"throttleit": "2.1.0"
},
"devDependencies": {
"@ai-sdk/test-server": "1.0.3",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.0.1",
"@testing-library/user-event": "^14.5.2",
"@types/node": "20.17.24",
"@types/react": "^18",
"@types/react-dom": "^18",
"@vercel/ai-tsconfig": "0.0.0",
"eslint": "8.57.1",
"eslint-config-vercel-ai": "0.0.0",
"jsdom": "^24.0.0",
"msw": "2.6.4",
"react-dom": "^18 || ^19",
"tsup": "^7.2.0",
"typescript": "5.8.3",
"zod": "3.25.76"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"react": "^18 || ~19.0.1 || ~19.1.2 || ^19.2.1"
}
},
"../../node_modules/.pnpm/@tailwindcss+postcss@4.1.8/node_modules/@tailwindcss/postcss": {
"version": "4.1.8",
"dev": true,
"license": "MIT",
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
"@tailwindcss/node": "4.1.8",
"@tailwindcss/oxide": "4.1.8",
"postcss": "^8.4.41",
"tailwindcss": "4.1.8"
},
"devDependencies": {
"@types/node": "^20.14.8",
"@types/postcss-import": "14.0.3",
"dedent": "1.6.0",
"internal-example-plugin": "0.0.0",
"postcss-import": "^16.1.0"
}
},
"../../node_modules/.pnpm/@types+node@22.15.21/node_modules/@types/node": {
"version": "22.15.21",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
}
},
"../../node_modules/.pnpm/@types+react-dom@19.1.5_@types+react@19.1.4/node_modules/@types/react-dom": {
"version": "19.1.5",
"dev": true,
"license": "MIT",
"peerDependencies": {
"@types/react": "^19.0.0"
}
},
"../../node_modules/.pnpm/@types+react@19.1.4/node_modules/@types/react": {
"version": "19.1.4",
"dev": true,
"license": "MIT",
"dependencies": {
"csstype": "^3.0.2"
}
},
"../../node_modules/.pnpm/ai@6.0.73_zod@4.3.6/node_modules/ai": {
"version": "6.0.73",
"license": "Apache-2.0",
"dependencies": {
"@ai-sdk/gateway": "3.0.36",
"@ai-sdk/provider": "3.0.7",
"@ai-sdk/provider-utils": "4.0.13",
"@opentelemetry/api": "1.9.0"
},
"devDependencies": {
"@ai-sdk/test-server": "1.0.3",
"@edge-runtime/vm": "^5.0.0",
"@types/json-schema": "7.0.15",
"@types/node": "20.17.24",
"@vercel/ai-tsconfig": "0.0.0",
"esbuild": "^0.24.2",
"eslint": "8.57.1",
"eslint-config-vercel-ai": "0.0.0",
"tsup": "^7.2.0",
"tsx": "^4.19.2",
"typescript": "5.8.3",
"zod": "3.25.76"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"zod": "^3.25.76 || ^4.1.8"
}
},
"../../node_modules/.pnpm/next@15.3.3_react-dom@19.1.0_react@19.1.0/node_modules/next": {
"version": "15.3.3",
"license": "MIT",
"dependencies": {
"@next/env": "15.3.3",
"@swc/counter": "0.1.3",
"@swc/helpers": "0.5.15",
"busboy": "1.6.0",
"caniuse-lite": "^1.0.30001579",
"postcss": "8.4.31",
"styled-jsx": "5.1.6"
},
"bin": {
"next": "dist/bin/next"
},
"devDependencies": {
"@ampproject/toolbox-optimizer": "2.8.3",
"@babel/code-frame": "7.22.5",
"@babel/core": "7.22.5",
"@babel/eslint-parser": "7.22.5",
"@babel/generator": "7.22.5",
"@babel/plugin-proposal-class-properties": "7.18.6",
"@babel/plugin-proposal-export-namespace-from": "7.18.9",
"@babel/plugin-proposal-numeric-separator": "7.18.6",
"@babel/plugin-proposal-object-rest-spread": "7.20.7",
"@babel/plugin-syntax-bigint": "7.8.3",
"@babel/plugin-syntax-dynamic-import": "7.8.3",
"@babel/plugin-syntax-import-attributes": "7.22.5",
"@babel/plugin-syntax-jsx": "7.22.5",
"@babel/plugin-transform-modules-commonjs": "7.22.5",
"@babel/plugin-transform-runtime": "7.22.5",
"@babel/preset-env": "7.22.5",
"@babel/preset-react": "7.22.5",
"@babel/preset-typescript": "7.22.5",
"@babel/runtime": "7.22.5",
"@babel/traverse": "7.22.5",
"@babel/types": "7.22.5",
"@capsizecss/metrics": "3.4.0",
"@edge-runtime/cookies": "6.0.0",
"@edge-runtime/ponyfill": "4.0.0",
"@edge-runtime/primitives": "6.0.0",
"@hapi/accept": "5.0.2",
"@jest/transform": "29.5.0",
"@jest/types": "29.5.0",
"@mswjs/interceptors": "0.23.0",
"@napi-rs/triples": "1.2.0",
"@next/font": "15.3.3",
"@next/polyfill-module": "15.3.3",
"@next/polyfill-nomodule": "15.3.3",
"@next/react-refresh-utils": "15.3.3",
"@next/swc": "15.3.3",
"@opentelemetry/api": "1.6.0",
"@playwright/test": "1.41.2",
"@storybook/addon-a11y": "8.6.0",
"@storybook/addon-essentials": "8.6.0",
"@storybook/addon-interactions": "8.6.0",
"@storybook/addon-webpack5-compiler-swc": "1.0.5",
"@storybook/blocks": "8.6.0",
"@storybook/react": "8.6.0",
"@storybook/react-webpack5": "8.6.0",
"@storybook/test": "8.6.0",
"@storybook/test-runner": "0.21.0",
"@swc/core": "1.9.3",
"@swc/types": "0.1.7",
"@taskr/clear": "1.1.0",
"@taskr/esnext": "1.1.0",
"@types/amphtml-validator": "1.0.0",
"@types/babel__code-frame": "7.0.2",
"@types/babel__core": "7.1.12",
"@types/babel__generator": "7.6.2",
"@types/babel__template": "7.4.0",
"@types/babel__traverse": "7.11.0",
"@types/bytes": "3.1.1",
"@types/ci-info": "2.0.0",
"@types/compression": "0.0.36",
"@types/content-disposition": "0.5.4",
"@types/content-type": "1.1.3",
"@types/cookie": "0.3.3",
"@types/cross-spawn": "6.0.0",
"@types/debug": "4.1.5",
"@types/express-serve-static-core": "4.17.33",
"@types/fresh": "0.5.0",
"@types/glob": "7.1.1",
"@types/jsonwebtoken": "9.0.0",
"@types/lodash": "4.14.198",
"@types/lodash.curry": "4.1.6",
"@types/path-to-regexp": "1.7.0",
"@types/picomatch": "2.3.3",
"@types/platform": "1.3.4",
"@types/react": "19.0.8",
"@types/react-dom": "19.0.3",
"@types/react-is": "18.2.4",
"@types/semver": "7.3.1",
"@types/send": "0.14.4",
"@types/shell-quote": "1.7.1",
"@types/tar": "6.1.5",
"@types/text-table": "0.2.1",
"@types/ua-parser-js": "0.7.36",
"@types/webpack-sources1": "npm:@types/webpack-sources@0.1.5",
"@types/ws": "8.2.0",
"@typescript/vfs": "1.6.1",
"@vercel/ncc": "0.34.0",
"@vercel/nft": "0.27.1",
"@vercel/turbopack-ecmascript-runtime": "*",
"acorn": "8.14.0",
"amphtml-validator": "1.0.38",
"anser": "1.4.9",
"arg": "4.1.0",
"assert": "2.0.0",
"async-retry": "1.2.3",
"async-sema": "3.0.0",
"axe-playwright": "2.0.3",
"babel-plugin-react-compiler": "19.0.0-beta-e552027-20250112",
"babel-plugin-transform-define": "2.0.0",
"babel-plugin-transform-react-remove-prop-types": "0.4.24",
"browserify-zlib": "0.2.0",
"browserslist": "4.22.2",
"buffer": "5.6.0",
"bytes": "3.1.1",
"ci-info": "watson/ci-info#f43f6a1cefff47fb361c88cf4b943fdbcaafe540",
"cli-select": "1.1.2",
"client-only": "0.0.1",
"commander": "12.1.0",
"comment-json": "3.0.3",
"compression": "1.7.4",
"conf": "5.0.0",
"constants-browserify": "1.0.0",
"content-disposition": "0.5.3",
"content-type": "1.0.4",
"cookie": "0.4.1",
"cross-env": "6.0.3",
"cross-spawn": "7.0.3",
"crypto-browserify": "3.12.0",
"css.escape": "1.5.1",
"cssnano-preset-default": "7.0.6",
"data-uri-to-buffer": "3.0.1",
"debug": "4.1.1",
"devalue": "2.0.1",
"domain-browser": "4.19.0",
"edge-runtime": "4.0.1",
"events": "3.3.0",
"find-up": "4.1.0",
"fresh": "0.5.2",
"glob": "7.1.7",
"gzip-size": "5.1.1",
"http-proxy": "1.18.1",
"http-proxy-agent": "5.0.0",
"https-browserify": "1.0.0",
"https-proxy-agent": "5.0.1",
"icss-utils": "5.1.0",
"ignore-loader": "0.1.2",
"image-size": "1.2.1",
"is-docker": "2.0.0",
"is-wsl": "2.2.0",
"jest-worker": "27.5.1",
"json5": "2.2.3",
"jsonwebtoken": "9.0.0",
"loader-runner": "4.3.0",
"loader-utils2": "npm:loader-utils@2.0.0",
"loader-utils3": "npm:loader-utils@3.1.3",
"lodash.curry": "4.1.1",
"mini-css-extract-plugin": "2.4.4",
"msw": "2.3.0",
"nanoid": "3.1.32",
"native-url": "0.3.4",
"neo-async": "2.6.1",
"node-html-parser": "5.3.3",
"ora": "4.0.4",
"os-browserify": "0.3.0",
"p-limit": "3.1.0",
"p-queue": "6.6.2",
"path-browserify": "1.0.1",
"path-to-regexp": "6.1.0",
"picomatch": "4.0.1",
"postcss-flexbugs-fixes": "5.0.2",
"postcss-modules-extract-imports": "3.0.0",
"postcss-modules-local-by-default": "4.2.0",
"postcss-modules-scope": "3.0.0",
"postcss-modules-values": "4.0.0",
"postcss-preset-env": "7.4.3",
"postcss-safe-parser": "6.0.0",
"postcss-scss": "4.0.3",
"postcss-value-parser": "4.2.0",
"process": "0.11.10",
"punycode": "2.1.1",
"querystring-es3": "0.2.1",
"raw-body": "2.4.1",
"react-refresh": "0.12.0",
"regenerator-runtime": "0.13.4",
"sass-loader": "15.0.0",
"schema-utils2": "npm:schema-utils@2.7.1",
"schema-utils3": "npm:schema-utils@3.0.0",
"semver": "7.3.2",
"send": "0.17.1",
"server-only": "0.0.1",
"setimmediate": "1.0.5",
"shell-quote": "1.7.3",
"source-map": "0.6.1",
"source-map-loader": "5.0.0",
"source-map08": "npm:source-map@0.8.0-beta.0",
"stacktrace-parser": "0.1.10",
"storybook": "8.6.0",
"stream-browserify": "3.0.0",
"stream-http": "3.1.1",
"strict-event-emitter": "0.5.0",
"string_decoder": "1.3.0",
"string-hash": "1.1.3",
"strip-ansi": "6.0.0",
"superstruct": "1.0.3",
"tar": "6.1.15",
"taskr": "1.1.0",
"terser": "5.27.0",
"terser-webpack-plugin": "5.3.9",
"text-table": "0.2.0",
"timers-browserify": "2.0.12",
"tty-browserify": "0.0.1",
"typescript": "5.8.2",
"ua-parser-js": "1.0.35",
"unistore": "3.4.1",
"util": "0.12.4",
"vm-browserify": "1.1.2",
"watchpack": "2.4.0",
"web-vitals": "4.2.1",
"webpack": "5.98.0",
"webpack-sources1": "npm:webpack-sources@1.4.3",
"webpack-sources3": "npm:webpack-sources@3.2.3",
"ws": "8.2.3",
"zod": "3.22.3",
"zod-validation-error": "3.4.0"
},
"engines": {
"node": "^18.18.0 || ^19.8.0 || >= 20.0.0"
},
"optionalDependencies": {
"@next/swc-darwin-arm64": "15.3.3",
"@next/swc-darwin-x64": "15.3.3",
"@next/swc-linux-arm64-gnu": "15.3.3",
"@next/swc-linux-arm64-musl": "15.3.3",
"@next/swc-linux-x64-gnu": "15.3.3",
"@next/swc-linux-x64-musl": "15.3.3",
"@next/swc-win32-arm64-msvc": "15.3.3",
"@next/swc-win32-x64-msvc": "15.3.3",
"sharp": "^0.34.1"
},
"peerDependencies": {
"@opentelemetry/api": "^1.1.0",
"@playwright/test": "^1.41.2",
"babel-plugin-react-compiler": "*",
"react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
"react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
"sass": "^1.3.0"
},
"peerDependenciesMeta": {
"@opentelemetry/api": {
"optional": true
},
"@playwright/test": {
"optional": true
},
"babel-plugin-react-compiler": {
"optional": true
},
"sass": {
"optional": true
}
}
},
"../../node_modules/.pnpm/react-dom@19.1.0_react@19.1.0/node_modules/react-dom": {
"version": "19.1.0",
"license": "MIT",
"dependencies": {
"scheduler": "^0.26.0"
},
"peerDependencies": {
"react": "^19.1.0"
}
},
"../../node_modules/.pnpm/react@19.1.0/node_modules/react": {
"version": "19.1.0",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"../../node_modules/.pnpm/tailwindcss@4.1.8/node_modules/tailwindcss": {
"version": "4.1.8",
"dev": true,
"license": "MIT",
"devDependencies": {
"@ampproject/remapping": "^2.3.0",
"@tailwindcss/oxide": "^4.1.8",
"@types/node": "^20.14.8",
"dedent": "1.6.0",
"lightningcss": "1.30.1",
"magic-string": "^0.30.17",
"source-map-js": "^1.2.1"
}
},
"../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript": {
"version": "5.9.3",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"devDependencies": {
"@dprint/formatter": "^0.4.1",
"@dprint/typescript": "0.93.4",
"@esfx/canceltoken": "^1.0.0",
"@eslint/js": "^9.20.0",
"@octokit/rest": "^21.1.1",
"@types/chai": "^4.3.20",
"@types/diff": "^7.0.1",
"@types/minimist": "^1.2.5",
"@types/mocha": "^10.0.10",
"@types/ms": "^0.7.34",
"@types/node": "latest",
"@types/source-map-support": "^0.5.10",
"@types/which": "^3.0.4",
"@typescript-eslint/rule-tester": "^8.24.1",
"@typescript-eslint/type-utils": "^8.24.1",
"@typescript-eslint/utils": "^8.24.1",
"azure-devops-node-api": "^14.1.0",
"c8": "^10.1.3",
"chai": "^4.5.0",
"chokidar": "^4.0.3",
"diff": "^7.0.0",
"dprint": "^0.49.0",
"esbuild": "^0.25.0",
"eslint": "^9.20.1",
"eslint-formatter-autolinkable-stylish": "^1.4.0",
"eslint-plugin-regexp": "^2.7.0",
"fast-xml-parser": "^4.5.2",
"glob": "^10.4.5",
"globals": "^15.15.0",
"hereby": "^1.10.0",
"jsonc-parser": "^3.3.1",
"knip": "^5.44.4",
"minimist": "^1.2.8",
"mocha": "^10.8.2",
"mocha-fivemat-progress-reporter": "^0.1.0",
"monocart-coverage-reports": "^2.12.1",
"ms": "^2.1.3",
"picocolors": "^1.1.1",
"playwright": "^1.50.1",
"source-map-support": "^0.5.21",
"tslib": "^2.8.1",
"typescript": "^5.7.3",
"typescript-eslint": "^8.24.1",
"which": "^3.0.1"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/@ai-sdk/react": {
"resolved": "../../node_modules/.pnpm/@ai-sdk+react@3.0.75_react@19.1.0_zod@4.3.6/node_modules/@ai-sdk/react",
"link": true
},
"node_modules/@tailwindcss/postcss": {
"resolved": "../../node_modules/.pnpm/@tailwindcss+postcss@4.1.8/node_modules/@tailwindcss/postcss",
"link": true
},
"node_modules/@types/node": {
"resolved": "../../node_modules/.pnpm/@types+node@22.15.21/node_modules/@types/node",
"link": true
},
"node_modules/@types/react": {
"resolved": "../../node_modules/.pnpm/@types+react@19.1.4/node_modules/@types/react",
"link": true
},
"node_modules/@types/react-dom": {
"resolved": "../../node_modules/.pnpm/@types+react-dom@19.1.5_@types+react@19.1.4/node_modules/@types/react-dom",
"link": true
},
"node_modules/ai": {
"resolved": "../../node_modules/.pnpm/ai@6.0.73_zod@4.3.6/node_modules/ai",
"link": true
},
"node_modules/next": {
"resolved": "../../node_modules/.pnpm/next@15.3.3_react-dom@19.1.0_react@19.1.0/node_modules/next",
"link": true
},
"node_modules/react": {
"resolved": "../../node_modules/.pnpm/react@19.1.0/node_modules/react",
"link": true
},
"node_modules/react-dom": {
"resolved": "../../node_modules/.pnpm/react-dom@19.1.0_react@19.1.0/node_modules/react-dom",
"link": true
},
"node_modules/tailwindcss": {
"resolved": "../../node_modules/.pnpm/tailwindcss@4.1.8/node_modules/tailwindcss",
"link": true
},
"node_modules/typescript": {
"resolved": "../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript",
"link": true
}
}
}

File diff suppressed because one or more lines are too long

441
ui/package-lock.json generated Normal file
View File

@ -0,0 +1,441 @@
{
"name": "openclaw-control-ui",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "openclaw-control-ui",
"dependencies": {
"@noble/ed25519": "3.0.0",
"dompurify": "^3.3.1",
"lit": "^3.3.2",
"marked": "^17.0.1",
"vite": "7.3.1"
},
"devDependencies": {
"@vitest/browser-playwright": "4.0.18",
"playwright": "^1.58.1",
"vitest": "4.0.18"
}
},
"../node_modules/.pnpm/@noble+ed25519@3.0.0/node_modules/@noble/ed25519": {
"version": "3.0.0",
"license": "MIT",
"devDependencies": {
"@noble/hashes": "2.0.0",
"@paulmillr/jsbt": "0.4.4",
"@types/node": "24.2.1",
"fast-check": "4.2.0",
"prettier": "3.6.2",
"typescript": "5.9.2"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"../node_modules/.pnpm/@vitest+browser-playwright@4.0.18_playwright@1.58.1_vite@7.3.1_vitest@4.0.18/node_modules/@vitest/browser-playwright": {
"version": "4.0.18",
"dev": true,
"license": "MIT",
"dependencies": {
"@vitest/browser": "4.0.18",
"@vitest/mocker": "4.0.18",
"tinyrainbow": "^3.0.3"
},
"devDependencies": {
"playwright": "^1.57.0",
"vitest": "4.0.18"
},
"funding": {
"url": "https://opencollective.com/vitest"
},
"peerDependencies": {
"playwright": "*",
"vitest": "4.0.18"
},
"peerDependenciesMeta": {
"playwright": {
"optional": false
}
}
},
"../node_modules/.pnpm/dompurify@3.3.1/node_modules/dompurify": {
"version": "3.3.1",
"license": "(MPL-2.0 OR Apache-2.0)",
"devDependencies": {
"@babel/core": "^7.17.8",
"@babel/preset-env": "^7.16.11",
"@rollup/plugin-babel": "^6.0.4",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-replace": "^6.0.1",
"@rollup/plugin-terser": "^0.4.4",
"@types/estree": "^1.0.0",
"@types/node": "^16.18.120",
"cross-env": "^7.0.3",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
"jquery": "^3.6.0",
"jsdom": "^20.0.0",
"karma": "^6.3.17",
"karma-browserstack-launcher": "^1.5.1",
"karma-chrome-launcher": "^3.1.0",
"karma-firefox-launcher": "^2.1.2",
"karma-qunit": "^4.1.2",
"karma-rollup-preprocessor": "^7.0.8",
"lodash.sample": "^4.2.1",
"minimist": "^1.2.6",
"npm-run-all": "^4.1.5",
"pre-commit": "^1.2.2",
"prettier": "^2.5.1",
"qunit": "^2.4.1",
"qunit-tap": "^1.5.0",
"rimraf": "^3.0.2",
"rollup": "^3.29.5",
"rollup-plugin-dts": "^6.1.1",
"rollup-plugin-includepaths": "^0.2.4",
"rollup-plugin-typescript2": "^0.36.0",
"tslib": "^2.7.0",
"typescript": "^5.6.3",
"xo": "^0.54.1"
},
"optionalDependencies": {
"@types/trusted-types": "^2.0.7"
}
},
"../node_modules/.pnpm/lit@3.3.2/node_modules/lit": {
"version": "3.3.2",
"license": "BSD-3-Clause",
"dependencies": {
"@lit/reactive-element": "^2.1.0",
"lit-element": "^4.2.0",
"lit-html": "^3.3.0"
},
"devDependencies": {
"@lit-internal/scripts": "^1.0.1",
"@webcomponents/shadycss": "^1.8.0",
"@webcomponents/template": "^1.4.4",
"@webcomponents/webcomponentsjs": "^2.8.0",
"tslib": "^2.0.3"
}
},
"../node_modules/.pnpm/marked@17.0.1/node_modules/marked": {
"version": "17.0.1",
"license": "MIT",
"bin": {
"marked": "bin/marked.js"
},
"devDependencies": {
"@arethetypeswrong/cli": "^0.18.2",
"@markedjs/eslint-config": "^1.0.14",
"@markedjs/testutils": "15.0.11-0",
"@semantic-release/commit-analyzer": "^13.0.1",
"@semantic-release/git": "^10.0.1",
"@semantic-release/github": "^12.0.2",
"@semantic-release/npm": "^13.1.2",
"@semantic-release/release-notes-generator": "^14.1.0",
"cheerio": "1.1.2",
"commonmark": "0.31.2",
"cross-env": "^10.1.0",
"dts-bundle-generator": "^9.5.1",
"esbuild": "^0.27.0",
"esbuild-plugin-umd-wrapper": "^3.0.0",
"eslint": "^9.39.1",
"highlight.js": "^11.11.1",
"markdown-it": "14.1.0",
"marked-highlight": "^2.2.3",
"marked-man": "^2.1.0",
"recheck": "^4.5.0",
"rimraf": "^6.1.0",
"semantic-release": "^25.0.1",
"titleize": "^4.0.0",
"tslib": "^2.8.1",
"typescript": "5.9.3"
},
"engines": {
"node": ">= 20"
}
},
"../node_modules/.pnpm/playwright@1.58.1/node_modules/playwright": {
"version": "1.58.1",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.58.1"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"fsevents": "2.3.2"
}
},
"../node_modules/.pnpm/vite@7.3.1_@types+node@25.1.0_jiti@2.6.1_tsx@4.21.0_yaml@2.8.2/node_modules/vite": {
"version": "7.3.1",
"license": "MIT",
"dependencies": {
"esbuild": "^0.27.0",
"fdir": "^6.5.0",
"picomatch": "^4.0.3",
"postcss": "^8.5.6",
"rollup": "^4.43.0",
"tinyglobby": "^0.2.15"
},
"bin": {
"vite": "bin/vite.js"
},
"devDependencies": {
"@babel/parser": "^7.28.5",
"@jridgewell/remapping": "^2.3.5",
"@jridgewell/trace-mapping": "^0.3.31",
"@oxc-project/types": "0.95.0",
"@polka/compression": "^1.0.0-next.25",
"@rolldown/pluginutils": "^1.0.0-beta.52",
"@rollup/plugin-alias": "^5.1.1",
"@rollup/plugin-commonjs": "^29.0.0",
"@rollup/plugin-dynamic-import-vars": "2.1.4",
"@rollup/pluginutils": "^5.3.0",
"@types/escape-html": "^1.0.4",
"@types/pnpapi": "^0.0.5",
"artichokie": "^0.4.2",
"baseline-browser-mapping": "^2.8.32",
"cac": "^6.7.14",
"chokidar": "^3.6.0",
"connect": "^3.7.0",
"convert-source-map": "^2.0.0",
"cors": "^2.8.5",
"cross-spawn": "^7.0.6",
"dotenv": "^17.2.3",
"dotenv-expand": "^12.0.3",
"es-module-lexer": "^1.7.0",
"escape-html": "^1.0.3",
"estree-walker": "^3.0.3",
"etag": "^1.8.1",
"host-validation-middleware": "^0.1.2",
"http-proxy-3": "^1.22.0",
"launch-editor-middleware": "^2.12.0",
"lightningcss": "^1.30.2",
"magic-string": "^0.30.21",
"mlly": "^1.8.0",
"mrmime": "^2.0.1",
"nanoid": "^5.1.6",
"obug": "^1.0.2",
"open": "^10.2.0",
"parse5": "^8.0.0",
"pathe": "^2.0.3",
"periscopic": "^4.0.2",
"picocolors": "^1.1.1",
"postcss-import": "^16.1.1",
"postcss-load-config": "^6.0.1",
"postcss-modules": "^6.0.1",
"premove": "^4.0.0",
"resolve.exports": "^2.0.3",
"rolldown": "^1.0.0-beta.52",
"rolldown-plugin-dts": "^0.18.1",
"rollup-plugin-license": "^3.6.0",
"sass": "^1.94.2",
"sass-embedded": "^1.93.3",
"sirv": "^3.0.2",
"strip-literal": "^3.1.0",
"terser": "^5.44.1",
"tsconfck": "^3.1.6",
"ufo": "^1.6.1",
"ws": "^8.18.3"
},
"engines": {
"node": "^20.19.0 || >=22.12.0"
},
"funding": {
"url": "https://github.com/vitejs/vite?sponsor=1"
},
"optionalDependencies": {
"fsevents": "~2.3.3"
},
"peerDependencies": {
"@types/node": "^20.19.0 || >=22.12.0",
"jiti": ">=1.21.0",
"less": "^4.0.0",
"lightningcss": "^1.21.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
},
"jiti": {
"optional": true
},
"less": {
"optional": true
},
"lightningcss": {
"optional": true
},
"sass": {
"optional": true
},
"sass-embedded": {
"optional": true
},
"stylus": {
"optional": true
},
"sugarss": {
"optional": true
},
"terser": {
"optional": true
},
"tsx": {
"optional": true
},
"yaml": {
"optional": true
}
}
},
"../node_modules/.pnpm/vitest@4.0.18_@types+node@25.1.0_@vitest+browser-playwright@4.0.18_jiti@2.6.1_tsx@4.21.0_yaml@2.8.2/node_modules/vitest": {
"version": "4.0.18",
"dev": true,
"license": "MIT",
"dependencies": {
"@vitest/expect": "4.0.18",
"@vitest/mocker": "4.0.18",
"@vitest/pretty-format": "4.0.18",
"@vitest/runner": "4.0.18",
"@vitest/snapshot": "4.0.18",
"@vitest/spy": "4.0.18",
"@vitest/utils": "4.0.18",
"es-module-lexer": "^1.7.0",
"expect-type": "^1.2.2",
"magic-string": "^0.30.21",
"obug": "^2.1.1",
"pathe": "^2.0.3",
"picomatch": "^4.0.3",
"std-env": "^3.10.0",
"tinybench": "^2.9.0",
"tinyexec": "^1.0.2",
"tinyglobby": "^0.2.15",
"tinyrainbow": "^3.0.3",
"vite": "^6.0.0 || ^7.0.0",
"why-is-node-running": "^2.3.0"
},
"bin": {
"vitest": "vitest.mjs"
},
"devDependencies": {
"@antfu/install-pkg": "^1.1.0",
"@edge-runtime/vm": "^5.0.0",
"@jridgewell/trace-mapping": "0.3.31",
"@opentelemetry/api": "^1.9.0",
"@sinonjs/fake-timers": "14.0.0",
"@types/estree": "^1.0.8",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/jsdom": "^27.0.0",
"@types/node": "^24.10.1",
"@types/picomatch": "^4.0.2",
"@types/prompts": "^2.4.9",
"@types/sinonjs__fake-timers": "^8.1.5",
"acorn-walk": "^8.3.4",
"birpc": "^4.0.0",
"cac": "^6.7.14",
"empathic": "^2.0.0",
"flatted": "^3.3.3",
"happy-dom": "^20.0.11",
"jsdom": "^27.2.0",
"local-pkg": "^1.1.2",
"mime": "^4.1.0",
"prompts": "^2.4.2",
"strip-literal": "^3.1.0",
"ws": "^8.18.3"
},
"engines": {
"node": "^20.0.0 || ^22.0.0 || >=24.0.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
},
"peerDependencies": {
"@edge-runtime/vm": "*",
"@opentelemetry/api": "^1.9.0",
"@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
"@vitest/browser-playwright": "4.0.18",
"@vitest/browser-preview": "4.0.18",
"@vitest/browser-webdriverio": "4.0.18",
"@vitest/ui": "4.0.18",
"happy-dom": "*",
"jsdom": "*"
},
"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/ui": {
"optional": true
},
"happy-dom": {
"optional": true
},
"jsdom": {
"optional": true
}
}
},
"node_modules/@noble/ed25519": {
"resolved": "../node_modules/.pnpm/@noble+ed25519@3.0.0/node_modules/@noble/ed25519",
"link": true
},
"node_modules/@vitest/browser-playwright": {
"resolved": "../node_modules/.pnpm/@vitest+browser-playwright@4.0.18_playwright@1.58.1_vite@7.3.1_vitest@4.0.18/node_modules/@vitest/browser-playwright",
"link": true
},
"node_modules/dompurify": {
"resolved": "../node_modules/.pnpm/dompurify@3.3.1/node_modules/dompurify",
"link": true
},
"node_modules/lit": {
"resolved": "../node_modules/.pnpm/lit@3.3.2/node_modules/lit",
"link": true
},
"node_modules/marked": {
"resolved": "../node_modules/.pnpm/marked@17.0.1/node_modules/marked",
"link": true
},
"node_modules/playwright": {
"resolved": "../node_modules/.pnpm/playwright@1.58.1/node_modules/playwright",
"link": true
},
"node_modules/vite": {
"resolved": "../node_modules/.pnpm/vite@7.3.1_@types+node@25.1.0_jiti@2.6.1_tsx@4.21.0_yaml@2.8.2/node_modules/vite",
"link": true
},
"node_modules/vitest": {
"resolved": "../node_modules/.pnpm/vitest@4.0.18_@types+node@25.1.0_@vitest+browser-playwright@4.0.18_jiti@2.6.1_tsx@4.21.0_yaml@2.8.2/node_modules/vitest",
"link": true
}
}
}