From 5d6bd4f429aad05dc225dff81ccac5c1d4d8528d Mon Sep 17 00:00:00 2001 From: abearxiong Date: Wed, 4 Feb 2026 13:20:12 +0800 Subject: [PATCH] Refactor client routes and add IP fetching functionality - Moved client route definitions to separate files for better organization. - Added new route to fetch client IP addresses, supporting both IPv4 and IPv6. - Implemented system information retrieval in the client routes. - Updated package dependencies to their latest versions. - Adjusted call route to prevent overwriting existing routes. --- assistant/package.json | 10 +- assistant/src/app.ts | 3 +- .../local-app-manager/assistant-app.ts | 20 ++- assistant/src/module/assistant/proxy/proxy.ts | 6 +- assistant/src/module/light-code/index.ts | 96 +++++++++----- assistant/src/module/light-code/run.ts | 29 +--- assistant/src/module/livecode/index.ts | 27 ++-- assistant/src/module/livecode/wss.ts | 3 +- assistant/src/routes/call/index.ts | 4 +- assistant/src/routes/client/index.ts | 86 +----------- assistant/src/routes/client/ip.ts | 72 ++++++++++ assistant/src/routes/client/system.ts | 85 ++++++++++++ assistant/src/routes/index.ts | 3 +- assistant/src/routes/light-code/index.ts | 0 assistant/src/routes/light-code/reload.ts | 5 + assistant/src/routes/manager/index.ts | 2 + assistant/src/routes/opencode/module/open.ts | 3 - assistant/src/services/init/package.json | 14 +- assistant/src/test/live-app.ts | 18 ++- package.json | 8 +- pnpm-lock.yaml | 125 +++++++----------- 21 files changed, 363 insertions(+), 256 deletions(-) create mode 100644 assistant/src/routes/client/ip.ts create mode 100644 assistant/src/routes/client/system.ts create mode 100644 assistant/src/routes/light-code/index.ts create mode 100644 assistant/src/routes/light-code/reload.ts create mode 100644 assistant/src/routes/manager/index.ts diff --git a/assistant/package.json b/assistant/package.json index c6cb5c7..2025691 100644 --- a/assistant/package.json +++ b/assistant/package.json @@ -44,16 +44,16 @@ "devDependencies": { "@inquirer/prompts": "^8.2.0", "@kevisual/ai": "^0.0.24", - "@kevisual/api": "^0.0.42", + "@kevisual/api": "^0.0.44", "@kevisual/load": "^0.0.6", "@kevisual/local-app-manager": "^0.1.32", "@kevisual/logger": "^0.0.4", "@kevisual/query": "0.0.39", "@kevisual/query-login": "0.0.7", - "@kevisual/router": "^0.0.67", + "@kevisual/router": "^0.0.70", "@kevisual/types": "^0.0.12", "@kevisual/use-config": "^1.0.30", - "@opencode-ai/plugin": "^1.1.48", + "@opencode-ai/plugin": "^1.1.49", "@types/bun": "^1.3.8", "@types/node": "^25.2.0", "@types/send": "^1.2.1", @@ -77,11 +77,11 @@ "access": "public" }, "dependencies": { - "@aws-sdk/client-s3": "^3.980.0", + "@aws-sdk/client-s3": "^3.981.0", "@kevisual/js-filter": "^0.0.5", "@kevisual/oss": "^0.0.19", "@kevisual/video-tools": "^0.0.13", - "@opencode-ai/sdk": "^1.1.48", + "@opencode-ai/sdk": "^1.1.49", "es-toolkit": "^1.44.0", "eventemitter3": "^5.0.4", "lowdb": "^7.0.1", diff --git a/assistant/src/app.ts b/assistant/src/app.ts index ca5379a..d771728 100644 --- a/assistant/src/app.ts +++ b/assistant/src/app.ts @@ -60,8 +60,9 @@ app.route({ description: '获取路由列表', }).define(async (ctx) => { const list = ctx.app.getList((item) => { - if (item?.path?.includes('auth') || item?.id?.includes('auth')) return false; + if (item?.path?.includes?.('auth') || item?.id?.includes?.('auth')) return false; return true; }) + console.log('路由列表:', list.length); ctx.body = { list } }).addTo(app); \ No newline at end of file diff --git a/assistant/src/module/assistant/local-app-manager/assistant-app.ts b/assistant/src/module/assistant/local-app-manager/assistant-app.ts index 52c22ed..c78822f 100644 --- a/assistant/src/module/assistant/local-app-manager/assistant-app.ts +++ b/assistant/src/module/assistant/local-app-manager/assistant-app.ts @@ -12,6 +12,7 @@ import { initApi } from '@kevisual/api/proxy' import { Query } from '@kevisual/query'; import { initLightCode } from '@/module/light-code/index.ts'; import { ModuleResolver } from './assistant-app-resolve.ts'; +import z from 'zod'; export class AssistantApp extends Manager { config: AssistantConfig; pagesPath: string; @@ -149,7 +150,9 @@ export class AssistantApp extends Manager { routerProxy.push({ type: 'lightcode', lightcode: { - check: true, + id: 'main', + sync: 'remote', + rootPath: path.join(this.config.configPath.appsDir, 'light-code', 'code'), } }) } @@ -162,9 +165,22 @@ export class AssistantApp extends Manager { continue; } if (proxyInfo.type === 'lightcode') { + const schema = z.object({ + rootPath: z.string().describe('light-code 代码存放路径'), + sync: z.enum(['remote', 'local', 'both']).describe('同步方式,remote: 仅从远程拉取,local: 仅上传本地代码,both: 双向同步').default('remote'), + }); + const parseRes = schema.safeParse(proxyInfo.lightcode); + if (!parseRes.success) { + console.warn('lightcode 配置错误', parseRes.error); + continue; + } + const lightcodeConfig = parseRes.data; + initLightCode({ router: this.mainApp, - config: this.config + config: this.config, + sync: lightcodeConfig.sync, + rootPath: lightcodeConfig.rootPath, }); continue; } diff --git a/assistant/src/module/assistant/proxy/proxy.ts b/assistant/src/module/assistant/proxy/proxy.ts index 5d584c8..2068434 100644 --- a/assistant/src/module/assistant/proxy/proxy.ts +++ b/assistant/src/module/assistant/proxy/proxy.ts @@ -48,10 +48,8 @@ export type ProxyInfo = { }, lightcode?: { id?: string; - /** - * 是否检测远程服务更新 - */ - check?: boolean; + sync?: 'remote' | 'local' | 'both'; + rootPath?: string; } }; diff --git a/assistant/src/module/light-code/index.ts b/assistant/src/module/light-code/index.ts index 409b9d5..920f8a0 100644 --- a/assistant/src/module/light-code/index.ts +++ b/assistant/src/module/light-code/index.ts @@ -1,8 +1,7 @@ import { App, QueryRouterServer } from '@kevisual/router'; import { AssistantInit } from '../../services/init/index.ts'; import path from 'node:path'; -import fs, { write } from 'node:fs'; -import os from 'node:os'; +import fs from 'node:fs'; import glob from 'fast-glob'; import { runCode } from './run.ts'; const codeDemoId = '0e700dc8-90dd-41b7-91dd-336ea51de3d2' @@ -35,44 +34,47 @@ const writeCodeDemo = async (appDir: string) => { } // writeCodeDemo(path.join(os.homedir(), 'kevisual', 'assistant-app', 'apps')); -type opts = { +type Opts = { router: QueryRouterServer | App config: AssistantConfig | AssistantInit - sync?: boolean + sync?: 'remote' | 'local' | 'both' + rootPath?: string } type LightCodeFile = { id?: string, code?: string, hash?: string, filepath: string } -export const initLightCode = async (opts: opts) => { +export const initLightCode = async (opts: Opts) => { // 注册 light-code 路由 console.log('初始化 light-code 路由'); const config = opts.config as AssistantInit; const app = opts.router; const token = config.getConfig()?.token || ''; const query = config.query; - const sync = opts.sync ?? true; + const sync = opts.sync ?? 'remote'; if (!config || !app) { console.error('initLightCode 缺少必要参数, config 或 app'); return; } - const appDir = config.configPath.appsDir; - const lightcodeDir = path.join(appDir, 'light-code', 'code'); + const lightcodeDir = opts.rootPath; if (!fs.existsSync(lightcodeDir)) { fs.mkdirSync(lightcodeDir, { recursive: true }); } let diffList: LightCodeFile[] = []; - const codeFiles = glob.sync(['**/*.ts', '**/*.js'], { - cwd: lightcodeDir, - onlyFiles: true, - }).map(file => { - return { - filepath: path.join(lightcodeDir, file), - // hash: getHash(path.join(lightcodeDir, file)) - } - }); + const findGlob = (opts: { cwd: string }) => { + return glob.sync(['**/*.ts', '**/*.js'], { + cwd: opts.cwd, + onlyFiles: true, + }).map(file => { + return { + filepath: path.join(opts.cwd, file), + // hash: getHash(path.join(lightcodeDir, file)) + } + }); + } + const codeFiles = findGlob({ cwd: lightcodeDir }); - if (sync) { + if (sync === 'remote' || sync === 'both') { const queryRes = await query.post({ path: 'light-code', key: 'list', @@ -100,13 +102,6 @@ export const initLightCode = async (opts: opts) => { fs.writeFileSync(item.filepath, item.code, 'utf-8'); // console.log(`新增 light-code 文件: ${item.filepath}`); } - - // 执行删除 - for (const filepath of toDelete) { - fs.unlinkSync(filepath.filepath); - // console.log(`删除 light-code 文件: ${filepath.filepath}`); - } - // 执行更新 for (const item of toUpdate) { fs.writeFileSync(item.filepath, item.code, 'utf-8'); @@ -117,23 +112,38 @@ export const initLightCode = async (opts: opts) => { // filepath: d.filepath, // hash: d.hash // })); + + if (sync === 'remote') { + // 执行删除 + for (const filepath of toDelete) { + // console.log(`删除 light-code 文件: ${filepath.filepath}`); + const parentDir = path.dirname(filepath.filepath); + // console.log('parentDir', parentDir, lightcodeDir); + if (parentDir === lightcodeDir) { + fs.unlinkSync(filepath.filepath); + } + } + } + diffList = findGlob({ cwd: lightcodeDir }); } else { console.error('light-code 同步失败', queryRes.message); diffList = codeFiles; } - } else { + } else if (sync === 'local') { diffList = codeFiles; } for (const file of diffList) { const tsPath = file.filepath; - const runRes = await runCode(tsPath, { path: 'router', key: 'list' }, { timeout: 10000 }); + const runRes = await runCode(tsPath, { message: { path: 'router', key: 'list' } }, { timeout: 10000 }); + // console.log('light-code 运行结果', file.filepath, runRes); if (runRes.success) { const res = runRes.data; if (res.code === 200) { const list = res.data?.list || []; for (const routerItem of list) { + // console.log('注册 light-code 路由项:', routerItem.id, routerItem.path); if (routerItem.path?.includes('auth') || routerItem.path?.includes('router') || routerItem.path?.includes('call')) { continue; } @@ -144,6 +154,10 @@ export const initLightCode = async (opts: opts) => { } else { metadata.tags = ['light-code']; } + metadata.source = 'light-code'; + metadata['light-code'] = { + id: file.id + } app.route({ id: routerItem.id, path: `${routerItem.id}__${routerItem.path}`, @@ -153,8 +167,13 @@ export const initLightCode = async (opts: opts) => { middleware: ['auth'], }).define(async (ctx) => { const tokenUser = ctx.state?.tokenUser || {}; - const query = { ...ctx.query, tokenUser } - const runRes2 = await runCode(tsPath, query, { timeout: 30000 }); + const query = { ...ctx.query } + const runRes2 = await runCode(tsPath, { + message: query, + context: { + state: { tokenUser, user: tokenUser }, + } + }, { timeout: 30000 }); if (runRes2.success) { const res2 = runRes2.data; if (res2.code === 200) { @@ -166,11 +185,9 @@ export const initLightCode = async (opts: opts) => { ctx.throw(runRes2.error || 'Lightcode 路由执行失败'); } }).addTo(app, { - override: false, - // @ts-ignore overwrite: false });// 不允许覆盖已存在的路由 - + // console.log(`light-code 路由注册成功: [${routerItem.path}] ${routerItem.id} 来自文件: ${file.filepath}`); } } } else { @@ -178,4 +195,19 @@ export const initLightCode = async (opts: opts) => { } } console.log(`light-code 路由注册成功`, `注册${diffList.length}个路由`); +} + +export const clearLightCodeRoutes = (opts: Pick) => { + const app = opts.router; + if (!app) { + console.error('clearLightCodeRoutes 缺少必要参数, app'); + return; + } + const routes = app.getList(); + for (const route of routes) { + if (route.metadata?.source === 'light-code') { + // console.log(`删除 light-code 路由: ${route.path} ${route.id}`); + app.removeById(route.id); + } + } } \ No newline at end of file diff --git a/assistant/src/module/light-code/run.ts b/assistant/src/module/light-code/run.ts index 2534b4a..4da4d06 100644 --- a/assistant/src/module/light-code/run.ts +++ b/assistant/src/module/light-code/run.ts @@ -1,6 +1,6 @@ import { fork } from 'node:child_process' -import fs from 'fs'; - +import fs from 'node:fs'; +import { ListenProcessParams, ListenProcessResponse } from '@kevisual/router'; export const fileExists = (path: string): boolean => { try { fs.accessSync(path, fs.constants.F_OK); @@ -10,30 +10,12 @@ export const fileExists = (path: string): boolean => { } } -export type RunCodeParams = { - path?: string; - key?: string; - payload?: string; - [key: string]: any -} +export type RunCodeParams = ListenProcessParams type RunCodeOptions = { timeout?: number; // 超时时间,单位毫秒 [key: string]: any } -type RunCode = { - // 调用进程的功能 - success?: boolean - data?: { - // 调用router的结果 - code?: number - data?: any - message?: string - [key: string]: any - }; - error?: any - timestamp?: string - output?: string -} +type RunCode = ListenProcessResponse & { output?: string } export const runCode = async (tsPath: string, params: RunCodeParams = {}, opts?: RunCodeOptions): Promise => { return new Promise((resolve, reject) => { if (fileExists(tsPath) === false) { @@ -81,7 +63,7 @@ export const runCode = async (tsPath: string, params: RunCodeParams = {}, opts?: silent: true, // 启用 stdio 重定向 env: { ...process.env, - BUN_CHILD_PROCESS: 'true' // 标记为子进程 + KEVISUAL_CHILD_PROCESS: 'true' // 标记为子进程 } }) // 监听来自子进程的消息 @@ -150,6 +132,7 @@ export const runCode = async (tsPath: string, params: RunCodeParams = {}, opts?: // 向子进程发送消息 } catch (error) { + console.error('启动子进程失败:', error) resolveOnce({ success: false, error: `启动子进程失败: ${error instanceof Error ? error.message : '未知错误'}` diff --git a/assistant/src/module/livecode/index.ts b/assistant/src/module/livecode/index.ts index 3726343..ceef3ae 100644 --- a/assistant/src/module/livecode/index.ts +++ b/assistant/src/module/livecode/index.ts @@ -1,17 +1,21 @@ import { WSSManager } from './wss.ts'; import { App, Route } from '@kevisual/router' -import { WebSocketReq } from '@kevisual/router' +import { WebSocketReq, ListenProcessParams } from '@kevisual/router' import { EventEmitter } from 'eventemitter3'; import { customAlphabet } from 'nanoid'; - const letter = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; const customId = customAlphabet(letter, 16); +/** + * 实时注册的代码模块 + * + * 别人通过 WebSocket 连接到此模块,发送路由列表和请求数据 + */ export class LiveCode { wssManager: WSSManager; app: App; emitter: EventEmitter; constructor(app: App) { - this.wssManager = new WSSManager({ heartbeatInterval: 5000 }); + this.wssManager = new WSSManager({ heartbeatInterval: 6 * 5000 }); this.app = app; this.emitter = new EventEmitter(); console.log('[LiveCode] 模块已初始化'); @@ -46,9 +50,9 @@ export class LiveCode { return this.wssManager.getConnection(id) } async init(id: string): Promise<{ code: number, message?: string, data?: any }> { - return this.sendData({ path: 'router', key: 'list', }, id); + return this.sendData({ message: { path: 'router', key: 'list', } }, id); } - sendData(data: any, id: string): Promise<{ code: number, message?: string, data?: any }> { + sendData(data: ListenProcessParams, id: string): Promise<{ code: number, message?: string, data?: any }> { const reqId = customId() const wss = this.getWss(id); if (!wss) { @@ -102,6 +106,7 @@ export class LiveCode { description: route.description, metadata: { ...route.metadata, + source: 'livecode', liveCodeId: wid }, middleware: ['auth'], @@ -109,9 +114,15 @@ export class LiveCode { const { token, cookie, ...rest } = ctx.query; const tokenUser = ctx.state.tokernUser; const res = await this.sendData({ - id: route.id, - tokenUser, - payload: rest, + message: { + id: route.id, + payload: rest, + }, + context: { + state: { + tokenUser + } + } }, wid); // console.log('路由响应数据:', res); ctx.forward(res) diff --git a/assistant/src/module/livecode/wss.ts b/assistant/src/module/livecode/wss.ts index 557278d..10c6712 100644 --- a/assistant/src/module/livecode/wss.ts +++ b/assistant/src/module/livecode/wss.ts @@ -1,5 +1,6 @@ import { nanoid } from "nanoid"; import { WebSocketReq } from '@kevisual/router' +import { logger } from "../logger.ts"; type ConnectionInfo = { id: string; wsReq: WebSocketReq; @@ -59,7 +60,7 @@ export class WSSManager { const ws = connection.wsReq.ws; ws.send(JSON.stringify({ type: 'heartbeat', timestamp: new Date().toISOString() })); connection.lastHeartbeat = new Date(); - console.log(`[LiveCode] 发送心跳给连接 ${connection.id}`); + logger.debug(`[LiveCode] 发送心跳给连接 ${connection.id}`); }, this.heartbeatInterval); } diff --git a/assistant/src/routes/call/index.ts b/assistant/src/routes/call/index.ts index f92a185..9eb50c0 100644 --- a/assistant/src/routes/call/index.ts +++ b/assistant/src/routes/call/index.ts @@ -29,4 +29,6 @@ app.route({ ...ctx }); ctx.forward(res); -}).addTo(app) \ No newline at end of file +}).addTo(app, { + overwrite: false +}) \ No newline at end of file diff --git a/assistant/src/routes/client/index.ts b/assistant/src/routes/client/index.ts index 84ef1d4..3c979be 100644 --- a/assistant/src/routes/client/index.ts +++ b/assistant/src/routes/client/index.ts @@ -1,84 +1,2 @@ - -import { app, assistantConfig } from '../../app.ts'; -import { createSkill } from '@kevisual/router'; -import os from 'node:os'; -import { runCommand } from '@/services/app/index.ts'; -app - .route({ - path: 'client', - key: 'version', - description: '获取客户端版本号', - }) - .define(async (ctx) => { - ctx.body = 'v1.0.0'; - }) - .addTo(app); - -app - .route({ - path: 'client', - key: 'time', - description: '获取当前时间', - }) - .define(async (ctx) => { - ctx.body = { - time: new Date().getTime(), - date: new Date().toLocaleDateString(), - }; - }) - .addTo(app); - -// 调用 path: client key: system -app - .route({ - path: 'client', - key: 'system', - description: '获取系统信息', - metadata: { - tags: ['opencode'], - ...createSkill({ - skill: 'view-system-info', - title: '查看系统信息', - summary: '获取服务器操作系统平台、架构和版本信息', - }) - } - }) - .define(async (ctx) => { - const { platform, arch, release } = os; - ctx.body = { - platform: platform(), - arch: arch(), - release: release(), - }; - }) - .addTo(app); - - -app.route({ - path: 'client', - key: 'restart', - description: '重启客户端', - middleware: ['admin-auth'], - metadata: { - tags: ['opencode'], - ...createSkill({ - skill: 'restart-client', - title: '重启客户端', - summary: '重启当前运行的客户端应用程序', - }) - } -}).define(async (ctx) => { - const cmd = 'pm2 restart assistant-server --update-env'; - try { - runCommand(cmd, []); - ctx.body = { - message: '客户端重启命令已执行', - }; - } catch (error) { - ctx.status = 500; - ctx.body = { - message: '重启客户端失败', - error: error.message, - }; - } -}).addTo(app); \ No newline at end of file +import './ip.ts'; +import './system.ts' \ No newline at end of file diff --git a/assistant/src/routes/client/ip.ts b/assistant/src/routes/client/ip.ts new file mode 100644 index 0000000..8277706 --- /dev/null +++ b/assistant/src/routes/client/ip.ts @@ -0,0 +1,72 @@ + +import { app } from '../../app.ts'; +import { createSkill } from '@kevisual/router'; +import os from 'node:os'; + +const baseURLv4 = 'https://4.ipw.cn/'; +const baseURLv6 = 'https://6.ipw.cn/'; + +export const isIpv6 = (ip: string): boolean => { + return ip.includes(':'); +} + +export const isIpv4 = (ip: string): boolean => { + return ip.split('.').length === 4; +} +export const fetchIP = async (url: string): Promise => { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`Failed to fetch IP from ${url}: ${response.statusText}`); + } + const ip = (await response.text()).trim(); + return ip; +} + +app.route({ + path: 'client', + key: 'ip', + description: '获取客户端 IP 地址', + metadata: { + tags: ['opencode'], + ...createSkill({ + skill: 'view-client-ip', + title: '查看客户端 IP 地址', + summary: '获取当前客户端的 IP 地址信息', + }) + } +}) + .define(async (ctx) => { + const networkInterfaces = os.networkInterfaces(); + const ipAddresses: { type: string, address: string }[] = []; + for (const interfaceDetails of Object.values(networkInterfaces)) { + if (interfaceDetails) { + for (const detail of interfaceDetails) { + if (detail.family === 'IPv4' && !detail.internal) { + ipAddresses.push({ + type: 'IPv4-local', + address: detail.address, + }); + } + } + } + } + const res = await fetchIP(baseURLv6); + if (isIpv6(res)) { + ipAddresses.push({ + type: 'IPv6', + address: res, + }); + } + const res4 = await fetchIP(baseURLv4); + if (isIpv4(res4)) { + ipAddresses.push({ + type: 'IPv4', + address: res4, + }); + } + + ctx.body = { + ipAddresses, + }; + }) + .addTo(app); \ No newline at end of file diff --git a/assistant/src/routes/client/system.ts b/assistant/src/routes/client/system.ts new file mode 100644 index 0000000..ad07867 --- /dev/null +++ b/assistant/src/routes/client/system.ts @@ -0,0 +1,85 @@ + +import { app, assistantConfig } from '../../app.ts'; +import { createSkill } from '@kevisual/router'; +import os from 'node:os'; +import { runCommand } from '@/services/app/index.ts'; + +app + .route({ + path: 'client', + key: 'version', + description: '获取客户端版本号', + }) + .define(async (ctx) => { + ctx.body = 'v1.0.0'; + }) + .addTo(app); + +app + .route({ + path: 'client', + key: 'time', + description: '获取当前时间', + }) + .define(async (ctx) => { + ctx.body = { + time: new Date().getTime(), + date: new Date().toLocaleDateString(), + }; + }) + .addTo(app); + +// 调用 path: client key: system +app + .route({ + path: 'client', + key: 'system', + description: '获取系统信息', + metadata: { + tags: ['opencode'], + ...createSkill({ + skill: 'view-system-info', + title: '查看系统信息', + summary: '获取服务器操作系统平台、架构和版本信息', + }) + } + }) + .define(async (ctx) => { + const { platform, arch, release } = os; + ctx.body = { + platform: platform(), + arch: arch(), + release: release(), + }; + }) + .addTo(app); + + +app.route({ + path: 'client', + key: 'restart', + description: '重启客户端', + middleware: ['admin-auth'], + metadata: { + tags: ['opencode'], + ...createSkill({ + skill: 'restart-client', + title: '重启客户端', + summary: '重启当前运行的客户端应用程序', + }) + } +}).define(async (ctx) => { + const cmd = 'pm2 restart assistant-server --update-env'; + try { + runCommand(cmd, []); + ctx.body = { + message: '客户端重启命令已执行', + }; + } catch (error) { + ctx.status = 500; + ctx.body = { + message: '重启客户端失败', + error: error.message, + }; + } +}).addTo(app); diff --git a/assistant/src/routes/index.ts b/assistant/src/routes/index.ts index 3ea3584..54b0ddd 100644 --- a/assistant/src/routes/index.ts +++ b/assistant/src/routes/index.ts @@ -1,5 +1,6 @@ import { app, assistantConfig } from '../app.ts'; import './config/index.ts'; +import './client/index.ts'; import './shop-install/index.ts'; import './ai/index.ts'; import './user/index.ts'; @@ -7,7 +8,7 @@ import './call/index.ts' import './opencode/index.ts'; import './remote/index.ts'; -import './kevisual/index.ts' +// import './kevisual/index.ts' import { authCache } from '@/module/cache/auth.ts'; diff --git a/assistant/src/routes/light-code/index.ts b/assistant/src/routes/light-code/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/assistant/src/routes/light-code/reload.ts b/assistant/src/routes/light-code/reload.ts new file mode 100644 index 0000000..1a0734a --- /dev/null +++ b/assistant/src/routes/light-code/reload.ts @@ -0,0 +1,5 @@ +// TODO: 重载 light-code +import { initLightCode } from "@/module/light-code/index.ts"; + +// 下载最新代码,覆盖本地文件 +// 重新启动 light-code 相关服务 \ No newline at end of file diff --git a/assistant/src/routes/manager/index.ts b/assistant/src/routes/manager/index.ts new file mode 100644 index 0000000..565ebf2 --- /dev/null +++ b/assistant/src/routes/manager/index.ts @@ -0,0 +1,2 @@ +import { AssistantApp } from '../../module/assistant/local-app-manager/assistant-app.ts'; +// AssistantApp \ No newline at end of file diff --git a/assistant/src/routes/opencode/module/open.ts b/assistant/src/routes/opencode/module/open.ts index 2526807..3fdb34f 100644 --- a/assistant/src/routes/opencode/module/open.ts +++ b/assistant/src/routes/opencode/module/open.ts @@ -1,9 +1,6 @@ import { createOpencode, createOpencodeClient, OpencodeClient, } from "@opencode-ai/sdk"; -import { randomInt } from "es-toolkit"; import getPort from "get-port"; import os from "node:os"; -import path from "node:path"; -import fs from "node:fs"; import { execSync } from "node:child_process"; const DEFAULT_PORT = 5000; diff --git a/assistant/src/services/init/package.json b/assistant/src/services/init/package.json index 9f65453..037527e 100644 --- a/assistant/src/services/init/package.json +++ b/assistant/src/services/init/package.json @@ -12,15 +12,15 @@ "author": "", "license": "ISC", "dependencies": { - "@aws-sdk/client-s3": "^3.978.0", - "@kevisual/oss": "^0.0.16", - "@kevisual/query": "^0.0.38", + "@aws-sdk/client-s3": "^3.981.0", + "@kevisual/oss": "^0.0.19", + "@kevisual/query": "^0.0.39", "eventemitter3": "^5.0.4", - "@kevisual/router": "^0.0.64", - "@kevisual/use-config": "^1.0.28", + "@kevisual/router": "^0.0.70", + "@kevisual/use-config": "^1.0.30", "ioredis": "^5.9.2", "minio": "^8.0.6", - "pg": "^8.17.2", + "pg": "^8.18.0", "pm2": "^6.0.14", "sequelize": "^6.37.7", "crypto-js": "^4.2.0", @@ -35,6 +35,6 @@ "@kevisual/types": "^0.0.12", "@types/bun": "^1.3.8", "@types/crypto-js": "^4.2.2", - "@types/node": "^25.1.0" + "@types/node": "^25.2.0" } } \ No newline at end of file diff --git a/assistant/src/test/live-app.ts b/assistant/src/test/live-app.ts index b465549..c5d1952 100644 --- a/assistant/src/test/live-app.ts +++ b/assistant/src/test/live-app.ts @@ -1,5 +1,5 @@ -import { App } from '@kevisual/router' +import { App, ListenProcessResponse } from '@kevisual/router' import { WebSocket } from 'ws' import { ReconnectingWebSocket, handleCallApp } from '@kevisual/router/ws' import net from 'net'; @@ -23,7 +23,7 @@ app.createRouteList(); await new Promise((resolve) => setTimeout(resolve, 1000)); // 创建支持断开重连的 WebSocket 客户端 -const ws = new ReconnectingWebSocket('ws://localhost:51516/livecode/ws?id=test-live-app', { +const ws = new ReconnectingWebSocket('ws://localhost:51515/livecode/ws?id=test-live-app', { maxRetries: Infinity, // 无限重试 retryDelay: 1000, // 初始重试延迟 1 秒 maxDelay: 30000, // 最大延迟 30 秒 @@ -33,7 +33,7 @@ ws.onMessage(async (message) => { console.log('收到消息:', message); if (message.type === 'router' && message.id) { console.log('收到路由响应:', message); - const data = message?.data; + const data = message?.data as ListenProcessResponse; if (!data) { ws.send({ type: 'router', @@ -42,7 +42,17 @@ ws.onMessage(async (message) => { }); return; } - const res = await app.run(message.data); + const msg = data.message; + if (!msg) { + ws.send({ + type: 'router', + id: message.id, + data: { code: 500, message: 'No {message} received' } + }); + return; + } + const context = data.context || {}; + const res = await app.run(msg, context); console.log('路由处理结果:', res); ws.send({ type: 'router', diff --git a/package.json b/package.json index 51da605..14ad1a3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kevisual/cli", - "version": "0.1.0", + "version": "0.1.1", "description": "envision 命令行工具", "type": "module", "basename": "/root/cli", @@ -49,7 +49,7 @@ "@kevisual/auth": "^2.0.3", "@kevisual/context": "^0.0.4", "@kevisual/use-config": "^1.0.30", - "@opencode-ai/sdk": "^1.1.48", + "@opencode-ai/sdk": "^1.1.49", "@types/busboy": "^1.5.4", "busboy": "^1.6.0", "eventemitter3": "^5.0.4", @@ -62,7 +62,7 @@ "unstorage": "^1.17.4" }, "devDependencies": { - "@kevisual/api": "^0.0.42", + "@kevisual/api": "^0.0.44", "@kevisual/dts": "^0.0.3", "@kevisual/load": "^0.0.6", "@kevisual/logger": "^0.0.4", @@ -92,4 +92,4 @@ "publishConfig": { "access": "public" } -} +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 166a588..9db4f95 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,8 +24,8 @@ importers: specifier: ^1.0.30 version: 1.0.30(dotenv@17.2.3) '@opencode-ai/sdk': - specifier: ^1.1.48 - version: 1.1.48 + specifier: ^1.1.49 + version: 1.1.49 '@types/busboy': specifier: ^1.5.4 version: 1.5.4 @@ -58,8 +58,8 @@ importers: version: 1.17.4(idb-keyval@6.2.2) devDependencies: '@kevisual/api': - specifier: ^0.0.42 - version: 0.0.42 + specifier: ^0.0.44 + version: 0.0.44 '@kevisual/dts': specifier: ^0.0.3 version: 0.0.3(typescript@5.8.2) @@ -127,8 +127,8 @@ importers: assistant: dependencies: '@aws-sdk/client-s3': - specifier: ^3.980.0 - version: 3.980.0 + specifier: ^3.981.0 + version: 3.981.0 '@kevisual/js-filter': specifier: ^0.0.5 version: 0.0.5 @@ -139,8 +139,8 @@ importers: specifier: ^0.0.13 version: 0.0.13(dotenv@17.2.3)(supports-color@10.2.2) '@opencode-ai/sdk': - specifier: ^1.1.48 - version: 1.1.48 + specifier: ^1.1.49 + version: 1.1.49 es-toolkit: specifier: ^1.44.0 version: 1.44.0 @@ -170,8 +170,8 @@ importers: specifier: ^0.0.24 version: 0.0.24 '@kevisual/api': - specifier: ^0.0.42 - version: 0.0.42 + specifier: ^0.0.44 + version: 0.0.44 '@kevisual/load': specifier: ^0.0.6 version: 0.0.6 @@ -188,8 +188,8 @@ importers: specifier: 0.0.7 version: 0.0.7(@kevisual/query@0.0.39) '@kevisual/router': - specifier: ^0.0.67 - version: 0.0.67 + specifier: ^0.0.70 + version: 0.0.70 '@kevisual/types': specifier: ^0.0.12 version: 0.0.12 @@ -197,8 +197,8 @@ importers: specifier: ^1.0.30 version: 1.0.30(dotenv@17.2.3) '@opencode-ai/plugin': - specifier: ^1.1.48 - version: 1.1.48 + specifier: ^1.1.49 + version: 1.1.49 '@types/bun': specifier: ^1.3.8 version: 1.3.8 @@ -465,8 +465,8 @@ packages: '@aws-crypto/util@5.2.0': resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} - '@aws-sdk/client-s3@3.980.0': - resolution: {integrity: sha512-ch8QqKehyn1WOYbd8LyDbWjv84Z9OEj9qUxz8q3IOCU3ftAVkVR0wAuN96a1xCHnpOJcQZo3rOB08RlyKdkGxQ==} + '@aws-sdk/client-s3@3.981.0': + resolution: {integrity: sha512-zX3Xqm7V30J1D2II7WBL23SyqIIMD0wMzpiE+VosBxH6fAeXgrjIwSudCypNgnE1EK9OZoZMT3mJtkbUqUDdaA==} engines: {node: '>=20.0.0'} '@aws-sdk/client-sso@3.980.0': @@ -561,8 +561,8 @@ packages: resolution: {integrity: sha512-v4J8qYAWfOMcZ4MJUyatntOicTzEMaU7j3OpkRCGGFSL2NgXQ5VbxauIyORA+pxdKZ0qQG2tCQjQjZDlXEC3Ow==} engines: {node: '>=20.0.0'} - '@aws-sdk/signature-v4-multi-region@3.980.0': - resolution: {integrity: sha512-tO2jBj+ZIVM0nEgi1SyxWtaYGpuAJdsrugmWcI3/U2MPWCYsrvKasUo0026NvJJao38wyUq9B8XTG8Xu53j/VA==} + '@aws-sdk/signature-v4-multi-region@3.981.0': + resolution: {integrity: sha512-T/+h9df0DALAXXP+YfZ8bgmH6cEN7HAg6BqHe3t38GhHgQ1HULXwK5XMhiLWiHpytDdhLqiVH41SRgW8ynBl6Q==} engines: {node: '>=20.0.0'} '@aws-sdk/token-providers@3.980.0': @@ -581,6 +581,10 @@ packages: resolution: {integrity: sha512-AjKBNEc+rjOZQE1HwcD9aCELqg1GmUj1rtICKuY8cgwB73xJ4U/kNyqKKpN2k9emGqlfDY2D8itIp/vDc6OKpw==} engines: {node: '>=20.0.0'} + '@aws-sdk/util-endpoints@3.981.0': + resolution: {integrity: sha512-a8nXh/H3/4j+sxhZk+N3acSDlgwTVSZbX9i55dx41gI1H+geuonuRG+Shv3GZsCb46vzc08RK2qC78ypO8uRlg==} + engines: {node: '>=20.0.0'} + '@aws-sdk/util-locate-window@3.965.2': resolution: {integrity: sha512-qKgO7wAYsXzhwCHhdbaKFyxd83Fgs8/1Ka+jjSPrv2Ll7mB55Wbwlo0kkfMLh993/yEc8aoDIAc1Fz9h4Spi4Q==} engines: {node: '>=20.0.0'} @@ -1011,105 +1015,89 @@ packages: resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-arm@1.2.4': resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.2.4': resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-riscv64@1.2.4': resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} cpu: [riscv64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-s390x@1.2.4': resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-x64@1.2.4': resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.2.4': resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.2.4': resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-linux-arm64@0.34.5': resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-linux-arm@0.34.5': resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-linux-ppc64@0.34.5': resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] - libc: [glibc] '@img/sharp-linux-riscv64@0.34.5': resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [riscv64] os: [linux] - libc: [glibc] '@img/sharp-linux-s390x@0.34.5': resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-linux-x64@0.34.5': resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-linuxmusl-arm64@0.34.5': resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-linuxmusl-x64@0.34.5': resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-wasm32@0.34.5': resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} @@ -1300,8 +1288,8 @@ packages: '@kevisual/api@0.0.28': resolution: {integrity: sha512-WQluRlu2qGM1qktIhPLODie8x382a6jEMfFOcay/rnkCgXK0BRpnqOKwlX7IMLdMqka7GY/BD69kSMnK1Exf5g==} - '@kevisual/api@0.0.42': - resolution: {integrity: sha512-Bn5G+ZzGEPoJdvd5U3xWHGY0oidQj23gt1YAWvTqjm0frDJfJ4Q2WT9Xjb1ZdJ/YBcfaNe9yEoMCpFNdUls/mw==} + '@kevisual/api@0.0.44': + resolution: {integrity: sha512-KA2b17pxW1pTPWa4zsTSRTiGTmwdkIesV1ig51MyISUllita5VPqZ6UYYDJQTHuPzYcIkuodQ9iWTEZNM9AkFw==} '@kevisual/app@0.0.1': resolution: {integrity: sha512-PEx8P3l0iNSqrz9Ib9kVCYfqNMX6/LfNu+cEafmY6ECP1cV5Vmv+TH2fuasMosKjtbH2fAdDi97sbd29tdEK+g==} @@ -1372,8 +1360,8 @@ packages: '@kevisual/router@0.0.51': resolution: {integrity: sha512-i9qYBeS/um78oC912oWJD3iElB+5NTKyTrz1Hzf4DckiUFnjLL81UPwjIh5I2l9+ul0IZ/Pxx+sFSF99fJkzKg==} - '@kevisual/router@0.0.67': - resolution: {integrity: sha512-SKQDc9RUSUqpcVA4Y05rl525zmHcyl4JlHdFyBhatNRMBQdKCVd8rBAojnyz4gNmUU9bY+gxM87f30dHsQkRAw==} + '@kevisual/router@0.0.70': + resolution: {integrity: sha512-vXlIj9jRufhcIfeuPWemjSI+dxdzSmIBq5eRxQzqEfAJ7k+mBPhoI4KxH8vHnwyL30bqm8EdODL/p6Wg8uBw3g==} '@kevisual/types@0.0.12': resolution: {integrity: sha512-zJXH2dosir3jVrQ6QG4i0+iLQeT9gJ3H+cKXs8ReWboxBSYzUZO78XssVeVrFPsJ33iaAqo4q3DWbSS1dWGn7Q==} @@ -1439,11 +1427,11 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@opencode-ai/plugin@1.1.48': - resolution: {integrity: sha512-KkaSMevXmz7tOwYDMJeWiXE5N8LmRP18qWI5Xhv3+c+FdGPL+l1hQrjSgyv3k7Co7qpCyW3kAUESBB7BzIOl2w==} + '@opencode-ai/plugin@1.1.49': + resolution: {integrity: sha512-+FEE730fLJtoHCta5MXixOIzI9Cjos700QDNnAx6mA8YjFzO+kABnyqLQrCgZ9wUPJgiKH9bnHxT7AdRjWsNPw==} - '@opencode-ai/sdk@1.1.48': - resolution: {integrity: sha512-j5/79X45fUPWVD2Ffm/qvwLclDCdPeV+TYMDrm9to0p4pmzhmeKevCsyiRdLg0o0HE3AFRUnOo2rdO9NetN79A==} + '@opencode-ai/sdk@1.1.49': + resolution: {integrity: sha512-F5ZkgiqOiV+z3U4zeBLvrmNZv5MwNFMTWM+HWhChD+/UEswIebQKk9UMz9lPX4fswexIJdFPwFI/TBdNyZfKMg==} '@oslojs/encoding@1.1.0': resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==} @@ -1894,67 +1882,56 @@ packages: resolution: {integrity: sha512-gTJ/JnnjCMc15uwB10TTATBEhK9meBIY+gXP4s0sHD1zHOaIh4Dmy1X9wup18IiY9tTNk5gJc4yx9ctj/fjrIw==} cpu: [arm] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.43.0': resolution: {integrity: sha512-ZJ3gZynL1LDSIvRfz0qXtTNs56n5DI2Mq+WACWZ7yGHFUEirHBRt7fyIk0NsCKhmRhn7WAcjgSkSVVxKlPNFFw==} cpu: [arm] os: [linux] - libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.43.0': resolution: {integrity: sha512-8FnkipasmOOSSlfucGYEu58U8cxEdhziKjPD2FIa0ONVMxvl/hmONtX/7y4vGjdUhjcTHlKlDhw3H9t98fPvyA==} cpu: [arm64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.43.0': resolution: {integrity: sha512-KPPyAdlcIZ6S9C3S2cndXDkV0Bb1OSMsX0Eelr2Bay4EsF9yi9u9uzc9RniK3mcUGCLhWY9oLr6er80P5DE6XA==} cpu: [arm64] os: [linux] - libc: [musl] '@rollup/rollup-linux-loongarch64-gnu@4.43.0': resolution: {integrity: sha512-HPGDIH0/ZzAZjvtlXj6g+KDQ9ZMHfSP553za7o2Odegb/BEfwJcR0Sw0RLNpQ9nC6Gy8s+3mSS9xjZ0n3rhcYg==} cpu: [loong64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-powerpc64le-gnu@4.43.0': resolution: {integrity: sha512-gEmwbOws4U4GLAJDhhtSPWPXUzDfMRedT3hFMyRAvM9Mrnj+dJIFIeL7otsv2WF3D7GrV0GIewW0y28dOYWkmw==} cpu: [ppc64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.43.0': resolution: {integrity: sha512-XXKvo2e+wFtXZF/9xoWohHg+MuRnvO29TI5Hqe9xwN5uN8NKUYy7tXUG3EZAlfchufNCTHNGjEx7uN78KsBo0g==} cpu: [riscv64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.43.0': resolution: {integrity: sha512-ruf3hPWhjw6uDFsOAzmbNIvlXFXlBQ4nk57Sec8E8rUxs/AI4HD6xmiiasOOx/3QxS2f5eQMKTAwk7KHwpzr/Q==} cpu: [riscv64] os: [linux] - libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.43.0': resolution: {integrity: sha512-QmNIAqDiEMEvFV15rsSnjoSmO0+eJLoKRD9EAa9rrYNwO/XRCtOGM3A5A0X+wmG+XRrw9Fxdsw+LnyYiZWWcVw==} cpu: [s390x] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.43.0': resolution: {integrity: sha512-jAHr/S0iiBtFyzjhOkAics/2SrXE092qyqEg96e90L3t9Op8OTzS6+IX0Fy5wCt2+KqeHAkti+eitV0wvblEoQ==} cpu: [x64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-musl@4.43.0': resolution: {integrity: sha512-3yATWgdeXyuHtBhrLt98w+5fKurdqvs8B53LaoKD7P7H7FKOONLsBVMNl9ghPQZQuYcceV5CDyPfyfGpMWD9mQ==} cpu: [x64] os: [linux] - libc: [musl] '@rollup/rollup-win32-arm64-msvc@4.43.0': resolution: {integrity: sha512-wVzXp2qDSCOpcBCT5WRWLmpJRIzv23valvcTwMHEobkjippNf+C3ys/+wf07poPkeNix0paTNemB2XrHr2TnGw==} @@ -2253,28 +2230,24 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [glibc] '@tailwindcss/oxide-linux-arm64-musl@4.1.18': resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [musl] '@tailwindcss/oxide-linux-x64-gnu@4.1.18': resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [glibc] '@tailwindcss/oxide-linux-x64-musl@4.1.18': resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [musl] '@tailwindcss/oxide-wasm32-wasi@4.1.18': resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} @@ -2398,9 +2371,6 @@ packages: '@types/send@1.2.1': resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==} - '@types/spark-md5@3.0.5': - resolution: {integrity: sha512-lWf05dnD42DLVKQJZrDHtWFidcLrHuip01CtnC2/S6AMhX4t9ZlEUj4iuRlAnts0PQk7KESOqKxeGE/b6sIPGg==} - '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} @@ -3651,28 +3621,24 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] lightningcss-linux-arm64-musl@1.30.2: resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [musl] lightningcss-linux-x64-gnu@1.30.2: resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [glibc] lightningcss-linux-x64-musl@1.30.2: resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [musl] lightningcss-win32-arm64-msvc@1.30.2: resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} @@ -5339,7 +5305,7 @@ snapshots: '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 - '@aws-sdk/client-s3@3.980.0': + '@aws-sdk/client-s3@3.981.0': dependencies: '@aws-crypto/sha1-browser': 5.2.0 '@aws-crypto/sha256-browser': 5.2.0 @@ -5357,9 +5323,9 @@ snapshots: '@aws-sdk/middleware-ssec': 3.972.3 '@aws-sdk/middleware-user-agent': 3.972.5 '@aws-sdk/region-config-resolver': 3.972.3 - '@aws-sdk/signature-v4-multi-region': 3.980.0 + '@aws-sdk/signature-v4-multi-region': 3.981.0 '@aws-sdk/types': 3.973.1 - '@aws-sdk/util-endpoints': 3.980.0 + '@aws-sdk/util-endpoints': 3.981.0 '@aws-sdk/util-user-agent-browser': 3.972.3 '@aws-sdk/util-user-agent-node': 3.972.3 '@smithy/config-resolver': 4.4.6 @@ -5712,7 +5678,7 @@ snapshots: '@smithy/types': 4.12.0 tslib: 2.8.1 - '@aws-sdk/signature-v4-multi-region@3.980.0': + '@aws-sdk/signature-v4-multi-region@3.981.0': dependencies: '@aws-sdk/middleware-sdk-s3': 3.972.5 '@aws-sdk/types': 3.973.1 @@ -5750,6 +5716,14 @@ snapshots: '@smithy/util-endpoints': 3.2.8 tslib: 2.8.1 + '@aws-sdk/util-endpoints@3.981.0': + dependencies: + '@aws-sdk/types': 3.973.1 + '@smithy/types': 4.12.0 + '@smithy/url-parser': 4.2.8 + '@smithy/util-endpoints': 3.2.8 + tslib: 2.8.1 + '@aws-sdk/util-locate-window@3.965.2': dependencies: tslib: 2.8.1 @@ -6440,11 +6414,10 @@ snapshots: fuse.js: 7.1.0 nanoid: 5.1.6 - '@kevisual/api@0.0.42': + '@kevisual/api@0.0.44': dependencies: '@kevisual/js-filter': 0.0.5 '@kevisual/load': 0.0.6 - '@types/spark-md5': 3.0.5 es-toolkit: 1.44.0 eventemitter3: 5.0.4 fuse.js: 7.1.0 @@ -6611,7 +6584,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@kevisual/router@0.0.67': {} + '@kevisual/router@0.0.70': + dependencies: + es-toolkit: 1.44.0 '@kevisual/types@0.0.12': {} @@ -6724,12 +6699,12 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 - '@opencode-ai/plugin@1.1.48': + '@opencode-ai/plugin@1.1.49': dependencies: - '@opencode-ai/sdk': 1.1.48 + '@opencode-ai/sdk': 1.1.49 zod: 4.1.8 - '@opencode-ai/sdk@1.1.48': {} + '@opencode-ai/sdk@1.1.49': {} '@oslojs/encoding@1.1.0': {} @@ -7892,8 +7867,6 @@ snapshots: dependencies: '@types/node': 25.2.0 - '@types/spark-md5@3.0.5': {} - '@types/trusted-types@2.0.7': {} '@types/unist@2.0.11': {}