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.
This commit is contained in:
2026-02-04 13:20:12 +08:00
parent 6212194f95
commit 5d6bd4f429
21 changed files with 363 additions and 256 deletions

View File

@@ -44,16 +44,16 @@
"devDependencies": { "devDependencies": {
"@inquirer/prompts": "^8.2.0", "@inquirer/prompts": "^8.2.0",
"@kevisual/ai": "^0.0.24", "@kevisual/ai": "^0.0.24",
"@kevisual/api": "^0.0.42", "@kevisual/api": "^0.0.44",
"@kevisual/load": "^0.0.6", "@kevisual/load": "^0.0.6",
"@kevisual/local-app-manager": "^0.1.32", "@kevisual/local-app-manager": "^0.1.32",
"@kevisual/logger": "^0.0.4", "@kevisual/logger": "^0.0.4",
"@kevisual/query": "0.0.39", "@kevisual/query": "0.0.39",
"@kevisual/query-login": "0.0.7", "@kevisual/query-login": "0.0.7",
"@kevisual/router": "^0.0.67", "@kevisual/router": "^0.0.70",
"@kevisual/types": "^0.0.12", "@kevisual/types": "^0.0.12",
"@kevisual/use-config": "^1.0.30", "@kevisual/use-config": "^1.0.30",
"@opencode-ai/plugin": "^1.1.48", "@opencode-ai/plugin": "^1.1.49",
"@types/bun": "^1.3.8", "@types/bun": "^1.3.8",
"@types/node": "^25.2.0", "@types/node": "^25.2.0",
"@types/send": "^1.2.1", "@types/send": "^1.2.1",
@@ -77,11 +77,11 @@
"access": "public" "access": "public"
}, },
"dependencies": { "dependencies": {
"@aws-sdk/client-s3": "^3.980.0", "@aws-sdk/client-s3": "^3.981.0",
"@kevisual/js-filter": "^0.0.5", "@kevisual/js-filter": "^0.0.5",
"@kevisual/oss": "^0.0.19", "@kevisual/oss": "^0.0.19",
"@kevisual/video-tools": "^0.0.13", "@kevisual/video-tools": "^0.0.13",
"@opencode-ai/sdk": "^1.1.48", "@opencode-ai/sdk": "^1.1.49",
"es-toolkit": "^1.44.0", "es-toolkit": "^1.44.0",
"eventemitter3": "^5.0.4", "eventemitter3": "^5.0.4",
"lowdb": "^7.0.1", "lowdb": "^7.0.1",

View File

@@ -60,8 +60,9 @@ app.route({
description: '获取路由列表', description: '获取路由列表',
}).define(async (ctx) => { }).define(async (ctx) => {
const list = ctx.app.getList((item) => { 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; return true;
}) })
console.log('路由列表:', list.length);
ctx.body = { list } ctx.body = { list }
}).addTo(app); }).addTo(app);

View File

@@ -12,6 +12,7 @@ import { initApi } from '@kevisual/api/proxy'
import { Query } from '@kevisual/query'; import { Query } from '@kevisual/query';
import { initLightCode } from '@/module/light-code/index.ts'; import { initLightCode } from '@/module/light-code/index.ts';
import { ModuleResolver } from './assistant-app-resolve.ts'; import { ModuleResolver } from './assistant-app-resolve.ts';
import z from 'zod';
export class AssistantApp extends Manager { export class AssistantApp extends Manager {
config: AssistantConfig; config: AssistantConfig;
pagesPath: string; pagesPath: string;
@@ -149,7 +150,9 @@ export class AssistantApp extends Manager {
routerProxy.push({ routerProxy.push({
type: 'lightcode', type: 'lightcode',
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; continue;
} }
if (proxyInfo.type === 'lightcode') { 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({ initLightCode({
router: this.mainApp, router: this.mainApp,
config: this.config config: this.config,
sync: lightcodeConfig.sync,
rootPath: lightcodeConfig.rootPath,
}); });
continue; continue;
} }

View File

@@ -48,10 +48,8 @@ export type ProxyInfo = {
}, },
lightcode?: { lightcode?: {
id?: string; id?: string;
/** sync?: 'remote' | 'local' | 'both';
* 是否检测远程服务更新 rootPath?: string;
*/
check?: boolean;
} }
}; };

View File

@@ -1,8 +1,7 @@
import { App, QueryRouterServer } from '@kevisual/router'; import { App, QueryRouterServer } from '@kevisual/router';
import { AssistantInit } from '../../services/init/index.ts'; import { AssistantInit } from '../../services/init/index.ts';
import path from 'node:path'; import path from 'node:path';
import fs, { write } from 'node:fs'; import fs from 'node:fs';
import os from 'node:os';
import glob from 'fast-glob'; import glob from 'fast-glob';
import { runCode } from './run.ts'; import { runCode } from './run.ts';
const codeDemoId = '0e700dc8-90dd-41b7-91dd-336ea51de3d2' 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')); // writeCodeDemo(path.join(os.homedir(), 'kevisual', 'assistant-app', 'apps'));
type opts = { type Opts = {
router: QueryRouterServer | App router: QueryRouterServer | App
config: AssistantConfig | AssistantInit config: AssistantConfig | AssistantInit
sync?: boolean sync?: 'remote' | 'local' | 'both'
rootPath?: string
} }
type LightCodeFile = { type LightCodeFile = {
id?: string, code?: string, hash?: string, filepath: string id?: string, code?: string, hash?: string, filepath: string
} }
export const initLightCode = async (opts: opts) => { export const initLightCode = async (opts: Opts) => {
// 注册 light-code 路由 // 注册 light-code 路由
console.log('初始化 light-code 路由'); console.log('初始化 light-code 路由');
const config = opts.config as AssistantInit; const config = opts.config as AssistantInit;
const app = opts.router; const app = opts.router;
const token = config.getConfig()?.token || ''; const token = config.getConfig()?.token || '';
const query = config.query; const query = config.query;
const sync = opts.sync ?? true; const sync = opts.sync ?? 'remote';
if (!config || !app) { if (!config || !app) {
console.error('initLightCode 缺少必要参数, config 或 app'); console.error('initLightCode 缺少必要参数, config 或 app');
return; return;
} }
const appDir = config.configPath.appsDir; const lightcodeDir = opts.rootPath;
const lightcodeDir = path.join(appDir, 'light-code', 'code');
if (!fs.existsSync(lightcodeDir)) { if (!fs.existsSync(lightcodeDir)) {
fs.mkdirSync(lightcodeDir, { recursive: true }); fs.mkdirSync(lightcodeDir, { recursive: true });
} }
let diffList: LightCodeFile[] = []; let diffList: LightCodeFile[] = [];
const codeFiles = glob.sync(['**/*.ts', '**/*.js'], { const findGlob = (opts: { cwd: string }) => {
cwd: lightcodeDir, return glob.sync(['**/*.ts', '**/*.js'], {
onlyFiles: true, cwd: opts.cwd,
}).map(file => { onlyFiles: true,
return { }).map(file => {
filepath: path.join(lightcodeDir, file), return {
// hash: getHash(path.join(lightcodeDir, file)) 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({ const queryRes = await query.post({
path: 'light-code', path: 'light-code',
key: 'list', key: 'list',
@@ -100,13 +102,6 @@ export const initLightCode = async (opts: opts) => {
fs.writeFileSync(item.filepath, item.code, 'utf-8'); fs.writeFileSync(item.filepath, item.code, 'utf-8');
// console.log(`新增 light-code 文件: ${item.filepath}`); // 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) { for (const item of toUpdate) {
fs.writeFileSync(item.filepath, item.code, 'utf-8'); fs.writeFileSync(item.filepath, item.code, 'utf-8');
@@ -117,23 +112,38 @@ export const initLightCode = async (opts: opts) => {
// filepath: d.filepath, // filepath: d.filepath,
// hash: d.hash // 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 { } else {
console.error('light-code 同步失败', queryRes.message); console.error('light-code 同步失败', queryRes.message);
diffList = codeFiles; diffList = codeFiles;
} }
} else { } else if (sync === 'local') {
diffList = codeFiles; diffList = codeFiles;
} }
for (const file of diffList) { for (const file of diffList) {
const tsPath = file.filepath; 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) { if (runRes.success) {
const res = runRes.data; const res = runRes.data;
if (res.code === 200) { if (res.code === 200) {
const list = res.data?.list || []; const list = res.data?.list || [];
for (const routerItem of 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')) { if (routerItem.path?.includes('auth') || routerItem.path?.includes('router') || routerItem.path?.includes('call')) {
continue; continue;
} }
@@ -144,6 +154,10 @@ export const initLightCode = async (opts: opts) => {
} else { } else {
metadata.tags = ['light-code']; metadata.tags = ['light-code'];
} }
metadata.source = 'light-code';
metadata['light-code'] = {
id: file.id
}
app.route({ app.route({
id: routerItem.id, id: routerItem.id,
path: `${routerItem.id}__${routerItem.path}`, path: `${routerItem.id}__${routerItem.path}`,
@@ -153,8 +167,13 @@ export const initLightCode = async (opts: opts) => {
middleware: ['auth'], middleware: ['auth'],
}).define(async (ctx) => { }).define(async (ctx) => {
const tokenUser = ctx.state?.tokenUser || {}; const tokenUser = ctx.state?.tokenUser || {};
const query = { ...ctx.query, tokenUser } const query = { ...ctx.query }
const runRes2 = await runCode(tsPath, query, { timeout: 30000 }); const runRes2 = await runCode(tsPath, {
message: query,
context: {
state: { tokenUser, user: tokenUser },
}
}, { timeout: 30000 });
if (runRes2.success) { if (runRes2.success) {
const res2 = runRes2.data; const res2 = runRes2.data;
if (res2.code === 200) { if (res2.code === 200) {
@@ -166,11 +185,9 @@ export const initLightCode = async (opts: opts) => {
ctx.throw(runRes2.error || 'Lightcode 路由执行失败'); ctx.throw(runRes2.error || 'Lightcode 路由执行失败');
} }
}).addTo(app, { }).addTo(app, {
override: false,
// @ts-ignore
overwrite: false overwrite: false
});// 不允许覆盖已存在的路由 });// 不允许覆盖已存在的路由
// console.log(`light-code 路由注册成功: [${routerItem.path}] ${routerItem.id} 来自文件: ${file.filepath}`);
} }
} }
} else { } else {
@@ -178,4 +195,19 @@ export const initLightCode = async (opts: opts) => {
} }
} }
console.log(`light-code 路由注册成功`, `注册${diffList.length}个路由`); console.log(`light-code 路由注册成功`, `注册${diffList.length}个路由`);
}
export const clearLightCodeRoutes = (opts: Pick<Opts, 'router'>) => {
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);
}
}
} }

View File

@@ -1,6 +1,6 @@
import { fork } from 'node:child_process' 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 => { export const fileExists = (path: string): boolean => {
try { try {
fs.accessSync(path, fs.constants.F_OK); fs.accessSync(path, fs.constants.F_OK);
@@ -10,30 +10,12 @@ export const fileExists = (path: string): boolean => {
} }
} }
export type RunCodeParams = { export type RunCodeParams = ListenProcessParams
path?: string;
key?: string;
payload?: string;
[key: string]: any
}
type RunCodeOptions = { type RunCodeOptions = {
timeout?: number; // 超时时间,单位毫秒 timeout?: number; // 超时时间,单位毫秒
[key: string]: any [key: string]: any
} }
type RunCode = { type RunCode = ListenProcessResponse & { output?: string }
// 调用进程的功能
success?: boolean
data?: {
// 调用router的结果
code?: number
data?: any
message?: string
[key: string]: any
};
error?: any
timestamp?: string
output?: string
}
export const runCode = async (tsPath: string, params: RunCodeParams = {}, opts?: RunCodeOptions): Promise<RunCode> => { export const runCode = async (tsPath: string, params: RunCodeParams = {}, opts?: RunCodeOptions): Promise<RunCode> => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (fileExists(tsPath) === false) { if (fileExists(tsPath) === false) {
@@ -81,7 +63,7 @@ export const runCode = async (tsPath: string, params: RunCodeParams = {}, opts?:
silent: true, // 启用 stdio 重定向 silent: true, // 启用 stdio 重定向
env: { env: {
...process.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) { } catch (error) {
console.error('启动子进程失败:', error)
resolveOnce({ resolveOnce({
success: false, success: false,
error: `启动子进程失败: ${error instanceof Error ? error.message : '未知错误'}` error: `启动子进程失败: ${error instanceof Error ? error.message : '未知错误'}`

View File

@@ -1,17 +1,21 @@
import { WSSManager } from './wss.ts'; import { WSSManager } from './wss.ts';
import { App, Route } from '@kevisual/router' import { App, Route } from '@kevisual/router'
import { WebSocketReq } from '@kevisual/router' import { WebSocketReq, ListenProcessParams } from '@kevisual/router'
import { EventEmitter } from 'eventemitter3'; import { EventEmitter } from 'eventemitter3';
import { customAlphabet } from 'nanoid'; import { customAlphabet } from 'nanoid';
const letter = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; const letter = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
const customId = customAlphabet(letter, 16); const customId = customAlphabet(letter, 16);
/**
* 实时注册的代码模块
*
* 别人通过 WebSocket 连接到此模块,发送路由列表和请求数据
*/
export class LiveCode { export class LiveCode {
wssManager: WSSManager; wssManager: WSSManager;
app: App; app: App;
emitter: EventEmitter; emitter: EventEmitter;
constructor(app: App) { constructor(app: App) {
this.wssManager = new WSSManager({ heartbeatInterval: 5000 }); this.wssManager = new WSSManager({ heartbeatInterval: 6 * 5000 });
this.app = app; this.app = app;
this.emitter = new EventEmitter(); this.emitter = new EventEmitter();
console.log('[LiveCode] 模块已初始化'); console.log('[LiveCode] 模块已初始化');
@@ -46,9 +50,9 @@ export class LiveCode {
return this.wssManager.getConnection(id) return this.wssManager.getConnection(id)
} }
async init(id: string): Promise<{ code: number, message?: string, data?: any }> { 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 reqId = customId()
const wss = this.getWss(id); const wss = this.getWss(id);
if (!wss) { if (!wss) {
@@ -102,6 +106,7 @@ export class LiveCode {
description: route.description, description: route.description,
metadata: { metadata: {
...route.metadata, ...route.metadata,
source: 'livecode',
liveCodeId: wid liveCodeId: wid
}, },
middleware: ['auth'], middleware: ['auth'],
@@ -109,9 +114,15 @@ export class LiveCode {
const { token, cookie, ...rest } = ctx.query; const { token, cookie, ...rest } = ctx.query;
const tokenUser = ctx.state.tokernUser; const tokenUser = ctx.state.tokernUser;
const res = await this.sendData({ const res = await this.sendData({
id: route.id, message: {
tokenUser, id: route.id,
payload: rest, payload: rest,
},
context: {
state: {
tokenUser
}
}
}, wid); }, wid);
// console.log('路由响应数据:', res); // console.log('路由响应数据:', res);
ctx.forward(res) ctx.forward(res)

View File

@@ -1,5 +1,6 @@
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import { WebSocketReq } from '@kevisual/router' import { WebSocketReq } from '@kevisual/router'
import { logger } from "../logger.ts";
type ConnectionInfo = { type ConnectionInfo = {
id: string; id: string;
wsReq: WebSocketReq; wsReq: WebSocketReq;
@@ -59,7 +60,7 @@ export class WSSManager {
const ws = connection.wsReq.ws; const ws = connection.wsReq.ws;
ws.send(JSON.stringify({ type: 'heartbeat', timestamp: new Date().toISOString() })); ws.send(JSON.stringify({ type: 'heartbeat', timestamp: new Date().toISOString() }));
connection.lastHeartbeat = new Date(); connection.lastHeartbeat = new Date();
console.log(`[LiveCode] 发送心跳给连接 ${connection.id}`); logger.debug(`[LiveCode] 发送心跳给连接 ${connection.id}`);
}, this.heartbeatInterval); }, this.heartbeatInterval);
} }

View File

@@ -29,4 +29,6 @@ app.route({
...ctx ...ctx
}); });
ctx.forward(res); ctx.forward(res);
}).addTo(app) }).addTo(app, {
overwrite: false
})

View File

@@ -1,84 +1,2 @@
import './ip.ts';
import { app, assistantConfig } from '../../app.ts'; import './system.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);

View File

@@ -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<string> => {
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);

View File

@@ -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);

View File

@@ -1,5 +1,6 @@
import { app, assistantConfig } from '../app.ts'; import { app, assistantConfig } from '../app.ts';
import './config/index.ts'; import './config/index.ts';
import './client/index.ts';
import './shop-install/index.ts'; import './shop-install/index.ts';
import './ai/index.ts'; import './ai/index.ts';
import './user/index.ts'; import './user/index.ts';
@@ -7,7 +8,7 @@ import './call/index.ts'
import './opencode/index.ts'; import './opencode/index.ts';
import './remote/index.ts'; import './remote/index.ts';
import './kevisual/index.ts' // import './kevisual/index.ts'
import { authCache } from '@/module/cache/auth.ts'; import { authCache } from '@/module/cache/auth.ts';

View File

View File

@@ -0,0 +1,5 @@
// TODO: 重载 light-code
import { initLightCode } from "@/module/light-code/index.ts";
// 下载最新代码,覆盖本地文件
// 重新启动 light-code 相关服务

View File

@@ -0,0 +1,2 @@
import { AssistantApp } from '../../module/assistant/local-app-manager/assistant-app.ts';
// AssistantApp

View File

@@ -1,9 +1,6 @@
import { createOpencode, createOpencodeClient, OpencodeClient, } from "@opencode-ai/sdk"; import { createOpencode, createOpencodeClient, OpencodeClient, } from "@opencode-ai/sdk";
import { randomInt } from "es-toolkit";
import getPort from "get-port"; import getPort from "get-port";
import os from "node:os"; import os from "node:os";
import path from "node:path";
import fs from "node:fs";
import { execSync } from "node:child_process"; import { execSync } from "node:child_process";
const DEFAULT_PORT = 5000; const DEFAULT_PORT = 5000;

View File

@@ -12,15 +12,15 @@
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@aws-sdk/client-s3": "^3.978.0", "@aws-sdk/client-s3": "^3.981.0",
"@kevisual/oss": "^0.0.16", "@kevisual/oss": "^0.0.19",
"@kevisual/query": "^0.0.38", "@kevisual/query": "^0.0.39",
"eventemitter3": "^5.0.4", "eventemitter3": "^5.0.4",
"@kevisual/router": "^0.0.64", "@kevisual/router": "^0.0.70",
"@kevisual/use-config": "^1.0.28", "@kevisual/use-config": "^1.0.30",
"ioredis": "^5.9.2", "ioredis": "^5.9.2",
"minio": "^8.0.6", "minio": "^8.0.6",
"pg": "^8.17.2", "pg": "^8.18.0",
"pm2": "^6.0.14", "pm2": "^6.0.14",
"sequelize": "^6.37.7", "sequelize": "^6.37.7",
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
@@ -35,6 +35,6 @@
"@kevisual/types": "^0.0.12", "@kevisual/types": "^0.0.12",
"@types/bun": "^1.3.8", "@types/bun": "^1.3.8",
"@types/crypto-js": "^4.2.2", "@types/crypto-js": "^4.2.2",
"@types/node": "^25.1.0" "@types/node": "^25.2.0"
} }
} }

View File

@@ -1,5 +1,5 @@
import { App } from '@kevisual/router' import { App, ListenProcessResponse } from '@kevisual/router'
import { WebSocket } from 'ws' import { WebSocket } from 'ws'
import { ReconnectingWebSocket, handleCallApp } from '@kevisual/router/ws' import { ReconnectingWebSocket, handleCallApp } from '@kevisual/router/ws'
import net from 'net'; import net from 'net';
@@ -23,7 +23,7 @@ app.createRouteList();
await new Promise((resolve) => setTimeout(resolve, 1000)); await new Promise((resolve) => setTimeout(resolve, 1000));
// 创建支持断开重连的 WebSocket 客户端 // 创建支持断开重连的 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, // 无限重试 maxRetries: Infinity, // 无限重试
retryDelay: 1000, // 初始重试延迟 1 秒 retryDelay: 1000, // 初始重试延迟 1 秒
maxDelay: 30000, // 最大延迟 30 秒 maxDelay: 30000, // 最大延迟 30 秒
@@ -33,7 +33,7 @@ ws.onMessage(async (message) => {
console.log('收到消息:', message); console.log('收到消息:', message);
if (message.type === 'router' && message.id) { if (message.type === 'router' && message.id) {
console.log('收到路由响应:', message); console.log('收到路由响应:', message);
const data = message?.data; const data = message?.data as ListenProcessResponse;
if (!data) { if (!data) {
ws.send({ ws.send({
type: 'router', type: 'router',
@@ -42,7 +42,17 @@ ws.onMessage(async (message) => {
}); });
return; 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); console.log('路由处理结果:', res);
ws.send({ ws.send({
type: 'router', type: 'router',

View File

@@ -1,6 +1,6 @@
{ {
"name": "@kevisual/cli", "name": "@kevisual/cli",
"version": "0.1.0", "version": "0.1.1",
"description": "envision 命令行工具", "description": "envision 命令行工具",
"type": "module", "type": "module",
"basename": "/root/cli", "basename": "/root/cli",
@@ -49,7 +49,7 @@
"@kevisual/auth": "^2.0.3", "@kevisual/auth": "^2.0.3",
"@kevisual/context": "^0.0.4", "@kevisual/context": "^0.0.4",
"@kevisual/use-config": "^1.0.30", "@kevisual/use-config": "^1.0.30",
"@opencode-ai/sdk": "^1.1.48", "@opencode-ai/sdk": "^1.1.49",
"@types/busboy": "^1.5.4", "@types/busboy": "^1.5.4",
"busboy": "^1.6.0", "busboy": "^1.6.0",
"eventemitter3": "^5.0.4", "eventemitter3": "^5.0.4",
@@ -62,7 +62,7 @@
"unstorage": "^1.17.4" "unstorage": "^1.17.4"
}, },
"devDependencies": { "devDependencies": {
"@kevisual/api": "^0.0.42", "@kevisual/api": "^0.0.44",
"@kevisual/dts": "^0.0.3", "@kevisual/dts": "^0.0.3",
"@kevisual/load": "^0.0.6", "@kevisual/load": "^0.0.6",
"@kevisual/logger": "^0.0.4", "@kevisual/logger": "^0.0.4",
@@ -92,4 +92,4 @@
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
} }
} }

125
pnpm-lock.yaml generated
View File

@@ -24,8 +24,8 @@ importers:
specifier: ^1.0.30 specifier: ^1.0.30
version: 1.0.30(dotenv@17.2.3) version: 1.0.30(dotenv@17.2.3)
'@opencode-ai/sdk': '@opencode-ai/sdk':
specifier: ^1.1.48 specifier: ^1.1.49
version: 1.1.48 version: 1.1.49
'@types/busboy': '@types/busboy':
specifier: ^1.5.4 specifier: ^1.5.4
version: 1.5.4 version: 1.5.4
@@ -58,8 +58,8 @@ importers:
version: 1.17.4(idb-keyval@6.2.2) version: 1.17.4(idb-keyval@6.2.2)
devDependencies: devDependencies:
'@kevisual/api': '@kevisual/api':
specifier: ^0.0.42 specifier: ^0.0.44
version: 0.0.42 version: 0.0.44
'@kevisual/dts': '@kevisual/dts':
specifier: ^0.0.3 specifier: ^0.0.3
version: 0.0.3(typescript@5.8.2) version: 0.0.3(typescript@5.8.2)
@@ -127,8 +127,8 @@ importers:
assistant: assistant:
dependencies: dependencies:
'@aws-sdk/client-s3': '@aws-sdk/client-s3':
specifier: ^3.980.0 specifier: ^3.981.0
version: 3.980.0 version: 3.981.0
'@kevisual/js-filter': '@kevisual/js-filter':
specifier: ^0.0.5 specifier: ^0.0.5
version: 0.0.5 version: 0.0.5
@@ -139,8 +139,8 @@ importers:
specifier: ^0.0.13 specifier: ^0.0.13
version: 0.0.13(dotenv@17.2.3)(supports-color@10.2.2) version: 0.0.13(dotenv@17.2.3)(supports-color@10.2.2)
'@opencode-ai/sdk': '@opencode-ai/sdk':
specifier: ^1.1.48 specifier: ^1.1.49
version: 1.1.48 version: 1.1.49
es-toolkit: es-toolkit:
specifier: ^1.44.0 specifier: ^1.44.0
version: 1.44.0 version: 1.44.0
@@ -170,8 +170,8 @@ importers:
specifier: ^0.0.24 specifier: ^0.0.24
version: 0.0.24 version: 0.0.24
'@kevisual/api': '@kevisual/api':
specifier: ^0.0.42 specifier: ^0.0.44
version: 0.0.42 version: 0.0.44
'@kevisual/load': '@kevisual/load':
specifier: ^0.0.6 specifier: ^0.0.6
version: 0.0.6 version: 0.0.6
@@ -188,8 +188,8 @@ importers:
specifier: 0.0.7 specifier: 0.0.7
version: 0.0.7(@kevisual/query@0.0.39) version: 0.0.7(@kevisual/query@0.0.39)
'@kevisual/router': '@kevisual/router':
specifier: ^0.0.67 specifier: ^0.0.70
version: 0.0.67 version: 0.0.70
'@kevisual/types': '@kevisual/types':
specifier: ^0.0.12 specifier: ^0.0.12
version: 0.0.12 version: 0.0.12
@@ -197,8 +197,8 @@ importers:
specifier: ^1.0.30 specifier: ^1.0.30
version: 1.0.30(dotenv@17.2.3) version: 1.0.30(dotenv@17.2.3)
'@opencode-ai/plugin': '@opencode-ai/plugin':
specifier: ^1.1.48 specifier: ^1.1.49
version: 1.1.48 version: 1.1.49
'@types/bun': '@types/bun':
specifier: ^1.3.8 specifier: ^1.3.8
version: 1.3.8 version: 1.3.8
@@ -465,8 +465,8 @@ packages:
'@aws-crypto/util@5.2.0': '@aws-crypto/util@5.2.0':
resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==}
'@aws-sdk/client-s3@3.980.0': '@aws-sdk/client-s3@3.981.0':
resolution: {integrity: sha512-ch8QqKehyn1WOYbd8LyDbWjv84Z9OEj9qUxz8q3IOCU3ftAVkVR0wAuN96a1xCHnpOJcQZo3rOB08RlyKdkGxQ==} resolution: {integrity: sha512-zX3Xqm7V30J1D2II7WBL23SyqIIMD0wMzpiE+VosBxH6fAeXgrjIwSudCypNgnE1EK9OZoZMT3mJtkbUqUDdaA==}
engines: {node: '>=20.0.0'} engines: {node: '>=20.0.0'}
'@aws-sdk/client-sso@3.980.0': '@aws-sdk/client-sso@3.980.0':
@@ -561,8 +561,8 @@ packages:
resolution: {integrity: sha512-v4J8qYAWfOMcZ4MJUyatntOicTzEMaU7j3OpkRCGGFSL2NgXQ5VbxauIyORA+pxdKZ0qQG2tCQjQjZDlXEC3Ow==} resolution: {integrity: sha512-v4J8qYAWfOMcZ4MJUyatntOicTzEMaU7j3OpkRCGGFSL2NgXQ5VbxauIyORA+pxdKZ0qQG2tCQjQjZDlXEC3Ow==}
engines: {node: '>=20.0.0'} engines: {node: '>=20.0.0'}
'@aws-sdk/signature-v4-multi-region@3.980.0': '@aws-sdk/signature-v4-multi-region@3.981.0':
resolution: {integrity: sha512-tO2jBj+ZIVM0nEgi1SyxWtaYGpuAJdsrugmWcI3/U2MPWCYsrvKasUo0026NvJJao38wyUq9B8XTG8Xu53j/VA==} resolution: {integrity: sha512-T/+h9df0DALAXXP+YfZ8bgmH6cEN7HAg6BqHe3t38GhHgQ1HULXwK5XMhiLWiHpytDdhLqiVH41SRgW8ynBl6Q==}
engines: {node: '>=20.0.0'} engines: {node: '>=20.0.0'}
'@aws-sdk/token-providers@3.980.0': '@aws-sdk/token-providers@3.980.0':
@@ -581,6 +581,10 @@ packages:
resolution: {integrity: sha512-AjKBNEc+rjOZQE1HwcD9aCELqg1GmUj1rtICKuY8cgwB73xJ4U/kNyqKKpN2k9emGqlfDY2D8itIp/vDc6OKpw==} resolution: {integrity: sha512-AjKBNEc+rjOZQE1HwcD9aCELqg1GmUj1rtICKuY8cgwB73xJ4U/kNyqKKpN2k9emGqlfDY2D8itIp/vDc6OKpw==}
engines: {node: '>=20.0.0'} 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': '@aws-sdk/util-locate-window@3.965.2':
resolution: {integrity: sha512-qKgO7wAYsXzhwCHhdbaKFyxd83Fgs8/1Ka+jjSPrv2Ll7mB55Wbwlo0kkfMLh993/yEc8aoDIAc1Fz9h4Spi4Q==} resolution: {integrity: sha512-qKgO7wAYsXzhwCHhdbaKFyxd83Fgs8/1Ka+jjSPrv2Ll7mB55Wbwlo0kkfMLh993/yEc8aoDIAc1Fz9h4Spi4Q==}
engines: {node: '>=20.0.0'} engines: {node: '>=20.0.0'}
@@ -1011,105 +1015,89 @@ packages:
resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [glibc]
'@img/sharp-libvips-linux-arm@1.2.4': '@img/sharp-libvips-linux-arm@1.2.4':
resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
libc: [glibc]
'@img/sharp-libvips-linux-ppc64@1.2.4': '@img/sharp-libvips-linux-ppc64@1.2.4':
resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==}
cpu: [ppc64] cpu: [ppc64]
os: [linux] os: [linux]
libc: [glibc]
'@img/sharp-libvips-linux-riscv64@1.2.4': '@img/sharp-libvips-linux-riscv64@1.2.4':
resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
libc: [glibc]
'@img/sharp-libvips-linux-s390x@1.2.4': '@img/sharp-libvips-linux-s390x@1.2.4':
resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==}
cpu: [s390x] cpu: [s390x]
os: [linux] os: [linux]
libc: [glibc]
'@img/sharp-libvips-linux-x64@1.2.4': '@img/sharp-libvips-linux-x64@1.2.4':
resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [glibc]
'@img/sharp-libvips-linuxmusl-arm64@1.2.4': '@img/sharp-libvips-linuxmusl-arm64@1.2.4':
resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [musl]
'@img/sharp-libvips-linuxmusl-x64@1.2.4': '@img/sharp-libvips-linuxmusl-x64@1.2.4':
resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [musl]
'@img/sharp-linux-arm64@0.34.5': '@img/sharp-linux-arm64@0.34.5':
resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [glibc]
'@img/sharp-linux-arm@0.34.5': '@img/sharp-linux-arm@0.34.5':
resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
libc: [glibc]
'@img/sharp-linux-ppc64@0.34.5': '@img/sharp-linux-ppc64@0.34.5':
resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [ppc64] cpu: [ppc64]
os: [linux] os: [linux]
libc: [glibc]
'@img/sharp-linux-riscv64@0.34.5': '@img/sharp-linux-riscv64@0.34.5':
resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
libc: [glibc]
'@img/sharp-linux-s390x@0.34.5': '@img/sharp-linux-s390x@0.34.5':
resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [s390x] cpu: [s390x]
os: [linux] os: [linux]
libc: [glibc]
'@img/sharp-linux-x64@0.34.5': '@img/sharp-linux-x64@0.34.5':
resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [glibc]
'@img/sharp-linuxmusl-arm64@0.34.5': '@img/sharp-linuxmusl-arm64@0.34.5':
resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [musl]
'@img/sharp-linuxmusl-x64@0.34.5': '@img/sharp-linuxmusl-x64@0.34.5':
resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [musl]
'@img/sharp-wasm32@0.34.5': '@img/sharp-wasm32@0.34.5':
resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==}
@@ -1300,8 +1288,8 @@ packages:
'@kevisual/api@0.0.28': '@kevisual/api@0.0.28':
resolution: {integrity: sha512-WQluRlu2qGM1qktIhPLODie8x382a6jEMfFOcay/rnkCgXK0BRpnqOKwlX7IMLdMqka7GY/BD69kSMnK1Exf5g==} resolution: {integrity: sha512-WQluRlu2qGM1qktIhPLODie8x382a6jEMfFOcay/rnkCgXK0BRpnqOKwlX7IMLdMqka7GY/BD69kSMnK1Exf5g==}
'@kevisual/api@0.0.42': '@kevisual/api@0.0.44':
resolution: {integrity: sha512-Bn5G+ZzGEPoJdvd5U3xWHGY0oidQj23gt1YAWvTqjm0frDJfJ4Q2WT9Xjb1ZdJ/YBcfaNe9yEoMCpFNdUls/mw==} resolution: {integrity: sha512-KA2b17pxW1pTPWa4zsTSRTiGTmwdkIesV1ig51MyISUllita5VPqZ6UYYDJQTHuPzYcIkuodQ9iWTEZNM9AkFw==}
'@kevisual/app@0.0.1': '@kevisual/app@0.0.1':
resolution: {integrity: sha512-PEx8P3l0iNSqrz9Ib9kVCYfqNMX6/LfNu+cEafmY6ECP1cV5Vmv+TH2fuasMosKjtbH2fAdDi97sbd29tdEK+g==} resolution: {integrity: sha512-PEx8P3l0iNSqrz9Ib9kVCYfqNMX6/LfNu+cEafmY6ECP1cV5Vmv+TH2fuasMosKjtbH2fAdDi97sbd29tdEK+g==}
@@ -1372,8 +1360,8 @@ packages:
'@kevisual/router@0.0.51': '@kevisual/router@0.0.51':
resolution: {integrity: sha512-i9qYBeS/um78oC912oWJD3iElB+5NTKyTrz1Hzf4DckiUFnjLL81UPwjIh5I2l9+ul0IZ/Pxx+sFSF99fJkzKg==} resolution: {integrity: sha512-i9qYBeS/um78oC912oWJD3iElB+5NTKyTrz1Hzf4DckiUFnjLL81UPwjIh5I2l9+ul0IZ/Pxx+sFSF99fJkzKg==}
'@kevisual/router@0.0.67': '@kevisual/router@0.0.70':
resolution: {integrity: sha512-SKQDc9RUSUqpcVA4Y05rl525zmHcyl4JlHdFyBhatNRMBQdKCVd8rBAojnyz4gNmUU9bY+gxM87f30dHsQkRAw==} resolution: {integrity: sha512-vXlIj9jRufhcIfeuPWemjSI+dxdzSmIBq5eRxQzqEfAJ7k+mBPhoI4KxH8vHnwyL30bqm8EdODL/p6Wg8uBw3g==}
'@kevisual/types@0.0.12': '@kevisual/types@0.0.12':
resolution: {integrity: sha512-zJXH2dosir3jVrQ6QG4i0+iLQeT9gJ3H+cKXs8ReWboxBSYzUZO78XssVeVrFPsJ33iaAqo4q3DWbSS1dWGn7Q==} resolution: {integrity: sha512-zJXH2dosir3jVrQ6QG4i0+iLQeT9gJ3H+cKXs8ReWboxBSYzUZO78XssVeVrFPsJ33iaAqo4q3DWbSS1dWGn7Q==}
@@ -1439,11 +1427,11 @@ packages:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
'@opencode-ai/plugin@1.1.48': '@opencode-ai/plugin@1.1.49':
resolution: {integrity: sha512-KkaSMevXmz7tOwYDMJeWiXE5N8LmRP18qWI5Xhv3+c+FdGPL+l1hQrjSgyv3k7Co7qpCyW3kAUESBB7BzIOl2w==} resolution: {integrity: sha512-+FEE730fLJtoHCta5MXixOIzI9Cjos700QDNnAx6mA8YjFzO+kABnyqLQrCgZ9wUPJgiKH9bnHxT7AdRjWsNPw==}
'@opencode-ai/sdk@1.1.48': '@opencode-ai/sdk@1.1.49':
resolution: {integrity: sha512-j5/79X45fUPWVD2Ffm/qvwLclDCdPeV+TYMDrm9to0p4pmzhmeKevCsyiRdLg0o0HE3AFRUnOo2rdO9NetN79A==} resolution: {integrity: sha512-F5ZkgiqOiV+z3U4zeBLvrmNZv5MwNFMTWM+HWhChD+/UEswIebQKk9UMz9lPX4fswexIJdFPwFI/TBdNyZfKMg==}
'@oslojs/encoding@1.1.0': '@oslojs/encoding@1.1.0':
resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==} resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==}
@@ -1894,67 +1882,56 @@ packages:
resolution: {integrity: sha512-gTJ/JnnjCMc15uwB10TTATBEhK9meBIY+gXP4s0sHD1zHOaIh4Dmy1X9wup18IiY9tTNk5gJc4yx9ctj/fjrIw==} resolution: {integrity: sha512-gTJ/JnnjCMc15uwB10TTATBEhK9meBIY+gXP4s0sHD1zHOaIh4Dmy1X9wup18IiY9tTNk5gJc4yx9ctj/fjrIw==}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.43.0': '@rollup/rollup-linux-arm-musleabihf@4.43.0':
resolution: {integrity: sha512-ZJ3gZynL1LDSIvRfz0qXtTNs56n5DI2Mq+WACWZ7yGHFUEirHBRt7fyIk0NsCKhmRhn7WAcjgSkSVVxKlPNFFw==} resolution: {integrity: sha512-ZJ3gZynL1LDSIvRfz0qXtTNs56n5DI2Mq+WACWZ7yGHFUEirHBRt7fyIk0NsCKhmRhn7WAcjgSkSVVxKlPNFFw==}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.43.0': '@rollup/rollup-linux-arm64-gnu@4.43.0':
resolution: {integrity: sha512-8FnkipasmOOSSlfucGYEu58U8cxEdhziKjPD2FIa0ONVMxvl/hmONtX/7y4vGjdUhjcTHlKlDhw3H9t98fPvyA==} resolution: {integrity: sha512-8FnkipasmOOSSlfucGYEu58U8cxEdhziKjPD2FIa0ONVMxvl/hmONtX/7y4vGjdUhjcTHlKlDhw3H9t98fPvyA==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.43.0': '@rollup/rollup-linux-arm64-musl@4.43.0':
resolution: {integrity: sha512-KPPyAdlcIZ6S9C3S2cndXDkV0Bb1OSMsX0Eelr2Bay4EsF9yi9u9uzc9RniK3mcUGCLhWY9oLr6er80P5DE6XA==} resolution: {integrity: sha512-KPPyAdlcIZ6S9C3S2cndXDkV0Bb1OSMsX0Eelr2Bay4EsF9yi9u9uzc9RniK3mcUGCLhWY9oLr6er80P5DE6XA==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-linux-loongarch64-gnu@4.43.0': '@rollup/rollup-linux-loongarch64-gnu@4.43.0':
resolution: {integrity: sha512-HPGDIH0/ZzAZjvtlXj6g+KDQ9ZMHfSP553za7o2Odegb/BEfwJcR0Sw0RLNpQ9nC6Gy8s+3mSS9xjZ0n3rhcYg==} resolution: {integrity: sha512-HPGDIH0/ZzAZjvtlXj6g+KDQ9ZMHfSP553za7o2Odegb/BEfwJcR0Sw0RLNpQ9nC6Gy8s+3mSS9xjZ0n3rhcYg==}
cpu: [loong64] cpu: [loong64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-powerpc64le-gnu@4.43.0': '@rollup/rollup-linux-powerpc64le-gnu@4.43.0':
resolution: {integrity: sha512-gEmwbOws4U4GLAJDhhtSPWPXUzDfMRedT3hFMyRAvM9Mrnj+dJIFIeL7otsv2WF3D7GrV0GIewW0y28dOYWkmw==} resolution: {integrity: sha512-gEmwbOws4U4GLAJDhhtSPWPXUzDfMRedT3hFMyRAvM9Mrnj+dJIFIeL7otsv2WF3D7GrV0GIewW0y28dOYWkmw==}
cpu: [ppc64] cpu: [ppc64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-gnu@4.43.0': '@rollup/rollup-linux-riscv64-gnu@4.43.0':
resolution: {integrity: sha512-XXKvo2e+wFtXZF/9xoWohHg+MuRnvO29TI5Hqe9xwN5uN8NKUYy7tXUG3EZAlfchufNCTHNGjEx7uN78KsBo0g==} resolution: {integrity: sha512-XXKvo2e+wFtXZF/9xoWohHg+MuRnvO29TI5Hqe9xwN5uN8NKUYy7tXUG3EZAlfchufNCTHNGjEx7uN78KsBo0g==}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-musl@4.43.0': '@rollup/rollup-linux-riscv64-musl@4.43.0':
resolution: {integrity: sha512-ruf3hPWhjw6uDFsOAzmbNIvlXFXlBQ4nk57Sec8E8rUxs/AI4HD6xmiiasOOx/3QxS2f5eQMKTAwk7KHwpzr/Q==} resolution: {integrity: sha512-ruf3hPWhjw6uDFsOAzmbNIvlXFXlBQ4nk57Sec8E8rUxs/AI4HD6xmiiasOOx/3QxS2f5eQMKTAwk7KHwpzr/Q==}
cpu: [riscv64] cpu: [riscv64]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-linux-s390x-gnu@4.43.0': '@rollup/rollup-linux-s390x-gnu@4.43.0':
resolution: {integrity: sha512-QmNIAqDiEMEvFV15rsSnjoSmO0+eJLoKRD9EAa9rrYNwO/XRCtOGM3A5A0X+wmG+XRrw9Fxdsw+LnyYiZWWcVw==} resolution: {integrity: sha512-QmNIAqDiEMEvFV15rsSnjoSmO0+eJLoKRD9EAa9rrYNwO/XRCtOGM3A5A0X+wmG+XRrw9Fxdsw+LnyYiZWWcVw==}
cpu: [s390x] cpu: [s390x]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.43.0': '@rollup/rollup-linux-x64-gnu@4.43.0':
resolution: {integrity: sha512-jAHr/S0iiBtFyzjhOkAics/2SrXE092qyqEg96e90L3t9Op8OTzS6+IX0Fy5wCt2+KqeHAkti+eitV0wvblEoQ==} resolution: {integrity: sha512-jAHr/S0iiBtFyzjhOkAics/2SrXE092qyqEg96e90L3t9Op8OTzS6+IX0Fy5wCt2+KqeHAkti+eitV0wvblEoQ==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.43.0': '@rollup/rollup-linux-x64-musl@4.43.0':
resolution: {integrity: sha512-3yATWgdeXyuHtBhrLt98w+5fKurdqvs8B53LaoKD7P7H7FKOONLsBVMNl9ghPQZQuYcceV5CDyPfyfGpMWD9mQ==} resolution: {integrity: sha512-3yATWgdeXyuHtBhrLt98w+5fKurdqvs8B53LaoKD7P7H7FKOONLsBVMNl9ghPQZQuYcceV5CDyPfyfGpMWD9mQ==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [musl]
'@rollup/rollup-win32-arm64-msvc@4.43.0': '@rollup/rollup-win32-arm64-msvc@4.43.0':
resolution: {integrity: sha512-wVzXp2qDSCOpcBCT5WRWLmpJRIzv23valvcTwMHEobkjippNf+C3ys/+wf07poPkeNix0paTNemB2XrHr2TnGw==} resolution: {integrity: sha512-wVzXp2qDSCOpcBCT5WRWLmpJRIzv23valvcTwMHEobkjippNf+C3ys/+wf07poPkeNix0paTNemB2XrHr2TnGw==}
@@ -2253,28 +2230,24 @@ packages:
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [glibc]
'@tailwindcss/oxide-linux-arm64-musl@4.1.18': '@tailwindcss/oxide-linux-arm64-musl@4.1.18':
resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [musl]
'@tailwindcss/oxide-linux-x64-gnu@4.1.18': '@tailwindcss/oxide-linux-x64-gnu@4.1.18':
resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [glibc]
'@tailwindcss/oxide-linux-x64-musl@4.1.18': '@tailwindcss/oxide-linux-x64-musl@4.1.18':
resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [musl]
'@tailwindcss/oxide-wasm32-wasi@4.1.18': '@tailwindcss/oxide-wasm32-wasi@4.1.18':
resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==}
@@ -2398,9 +2371,6 @@ packages:
'@types/send@1.2.1': '@types/send@1.2.1':
resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==} resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==}
'@types/spark-md5@3.0.5':
resolution: {integrity: sha512-lWf05dnD42DLVKQJZrDHtWFidcLrHuip01CtnC2/S6AMhX4t9ZlEUj4iuRlAnts0PQk7KESOqKxeGE/b6sIPGg==}
'@types/trusted-types@2.0.7': '@types/trusted-types@2.0.7':
resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
@@ -3651,28 +3621,24 @@ packages:
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [glibc]
lightningcss-linux-arm64-musl@1.30.2: lightningcss-linux-arm64-musl@1.30.2:
resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [musl]
lightningcss-linux-x64-gnu@1.30.2: lightningcss-linux-x64-gnu@1.30.2:
resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [glibc]
lightningcss-linux-x64-musl@1.30.2: lightningcss-linux-x64-musl@1.30.2:
resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [musl]
lightningcss-win32-arm64-msvc@1.30.2: lightningcss-win32-arm64-msvc@1.30.2:
resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==}
@@ -5339,7 +5305,7 @@ snapshots:
'@smithy/util-utf8': 2.3.0 '@smithy/util-utf8': 2.3.0
tslib: 2.8.1 tslib: 2.8.1
'@aws-sdk/client-s3@3.980.0': '@aws-sdk/client-s3@3.981.0':
dependencies: dependencies:
'@aws-crypto/sha1-browser': 5.2.0 '@aws-crypto/sha1-browser': 5.2.0
'@aws-crypto/sha256-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-ssec': 3.972.3
'@aws-sdk/middleware-user-agent': 3.972.5 '@aws-sdk/middleware-user-agent': 3.972.5
'@aws-sdk/region-config-resolver': 3.972.3 '@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/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-browser': 3.972.3
'@aws-sdk/util-user-agent-node': 3.972.3 '@aws-sdk/util-user-agent-node': 3.972.3
'@smithy/config-resolver': 4.4.6 '@smithy/config-resolver': 4.4.6
@@ -5712,7 +5678,7 @@ snapshots:
'@smithy/types': 4.12.0 '@smithy/types': 4.12.0
tslib: 2.8.1 tslib: 2.8.1
'@aws-sdk/signature-v4-multi-region@3.980.0': '@aws-sdk/signature-v4-multi-region@3.981.0':
dependencies: dependencies:
'@aws-sdk/middleware-sdk-s3': 3.972.5 '@aws-sdk/middleware-sdk-s3': 3.972.5
'@aws-sdk/types': 3.973.1 '@aws-sdk/types': 3.973.1
@@ -5750,6 +5716,14 @@ snapshots:
'@smithy/util-endpoints': 3.2.8 '@smithy/util-endpoints': 3.2.8
tslib: 2.8.1 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': '@aws-sdk/util-locate-window@3.965.2':
dependencies: dependencies:
tslib: 2.8.1 tslib: 2.8.1
@@ -6440,11 +6414,10 @@ snapshots:
fuse.js: 7.1.0 fuse.js: 7.1.0
nanoid: 5.1.6 nanoid: 5.1.6
'@kevisual/api@0.0.42': '@kevisual/api@0.0.44':
dependencies: dependencies:
'@kevisual/js-filter': 0.0.5 '@kevisual/js-filter': 0.0.5
'@kevisual/load': 0.0.6 '@kevisual/load': 0.0.6
'@types/spark-md5': 3.0.5
es-toolkit: 1.44.0 es-toolkit: 1.44.0
eventemitter3: 5.0.4 eventemitter3: 5.0.4
fuse.js: 7.1.0 fuse.js: 7.1.0
@@ -6611,7 +6584,9 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@kevisual/router@0.0.67': {} '@kevisual/router@0.0.70':
dependencies:
es-toolkit: 1.44.0
'@kevisual/types@0.0.12': {} '@kevisual/types@0.0.12': {}
@@ -6724,12 +6699,12 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5 '@nodelib/fs.scandir': 2.1.5
fastq: 1.17.1 fastq: 1.17.1
'@opencode-ai/plugin@1.1.48': '@opencode-ai/plugin@1.1.49':
dependencies: dependencies:
'@opencode-ai/sdk': 1.1.48 '@opencode-ai/sdk': 1.1.49
zod: 4.1.8 zod: 4.1.8
'@opencode-ai/sdk@1.1.48': {} '@opencode-ai/sdk@1.1.49': {}
'@oslojs/encoding@1.1.0': {} '@oslojs/encoding@1.1.0': {}
@@ -7892,8 +7867,6 @@ snapshots:
dependencies: dependencies:
'@types/node': 25.2.0 '@types/node': 25.2.0
'@types/spark-md5@3.0.5': {}
'@types/trusted-types@2.0.7': {} '@types/trusted-types@2.0.7': {}
'@types/unist@2.0.11': {} '@types/unist@2.0.11': {}