feat: add zod dependency and implement kevisual routes for CLI commands

- Added zod as a dependency in package.json.
- Enhanced assistant configuration to include skills and plugins directories.
- Implemented runCmd function to execute CLI commands in run.ts.
- Updated light-code module to use node:child_process.
- Created new kevisual routes for checking CLI login status and deploying web pages.
- Added restart functionality for OpenCode client in opencode module.
This commit is contained in:
2026-01-28 00:02:38 +08:00
parent 98f21d8aaa
commit 742a7a2992
11 changed files with 352 additions and 146 deletions

View File

@@ -87,6 +87,7 @@
"lowdb": "^7.0.1",
"lru-cache": "^11.2.4",
"pm2": "^6.0.14",
"unstorage": "^1.17.4"
"unstorage": "^1.17.4",
"zod": "^4.3.6"
}
}

View File

@@ -5,6 +5,7 @@ import { checkFileExists, createDir } from '../file/index.ts';
import { ProxyInfo } from '../proxy/proxy.ts';
import dotenv from 'dotenv';
import { logger } from '@/module/logger.ts';
import { z } from 'zod'
let kevisualDir = path.join(homedir(), 'kevisual');
const envKevisualDir = process.env.ASSISTANT_CONFIG_DIR
@@ -28,12 +29,15 @@ export const initConfig = (configRootPath: string) => {
const pageConfigPath = path.join(configDir, 'assistant-page-config.json');
const pagesDir = createDir(path.join(configDir, 'pages'));
const appsDir = createDir(path.join(configDir, 'apps'));
const skillsDir = createDir(path.join(configDir, 'skills'), false);
const pluginsDir = createDir(path.join(configDir, 'plugins'), false);
const appsConfigPath = path.join(configDir, 'assistant-apps-config.json');
const appPidPath = path.join(configDir, 'assistant-app.pid');
const envConfigPath = path.join(configDir, '.env');
return {
/**
* 助手配置文件路径
* 助手配置文件路径, assistant-app 目录
*/
configDir,
/**
@@ -41,7 +45,7 @@ export const initConfig = (configRootPath: string) => {
*/
configPath,
/**
* 服务目录, 后端服务目录
* 服务目录, 后端服务目录, apps 目录
*/
appsDir,
/**
@@ -49,7 +53,7 @@ export const initConfig = (configRootPath: string) => {
*/
appsConfigPath,
/**
* 应用目录, 前端应用目录
* 应用目录, 前端应用目录 pages 目录
*/
pagesDir,
/**
@@ -64,6 +68,14 @@ export const initConfig = (configRootPath: string) => {
* 环境变量配置文件路径
*/
envConfigPath,
/**
* 技能目录,配置给 opencode 去用的
*/
skillsDir,
/**
* 插件目录, 给 cli 用的,动态加载插件,每一个都是独立的
*/
pluginsDir,
};
};
export type ReturnInitConfigType = ReturnType<typeof initConfig>;

View File

@@ -0,0 +1,49 @@
import { spawn } from 'node:child_process'
type RunCmdOptions = {
cmd: string;
cwd?: string;
env?: Record<string, string>;
}
type RunResult = {
code: number;
data: string;
}
/**
* 运行命令行指令
* @param opts
* @returns
*/
export const runCmd = (opts: RunCmdOptions): Promise<RunResult> => {
const { cmd, cwd } = opts || {};
return new Promise<RunResult>((resolve) => {
const parts = cmd.split(' ');
const command = parts[0];
const args = parts.slice(1);
const proc = spawn(command, args, {
cwd: cwd || process.cwd(),
shell: true,
env: { ...process.env, ...opts?.env },
});
let stdout = '';
let stderr = '';
let result = ''
proc.stdout.on('data', (data: Buffer) => {
stdout += data.toString();
});
proc.stderr.on('data', (data: Buffer) => {
stderr += data.toString();
});
proc.on('close', (code: number) => {
result = stdout;
if (stderr) {
result += '\n' + stderr;
}
resolve({ code: code === 0 ? 200 : code, data: result });
});
proc.on('error', (err: Error) => {
resolve({ code: 500, data: err.message });
});
});
}

View File

@@ -1,4 +1,4 @@
import { fork } from 'child_process'
import { fork } from 'node:child_process'
import fs from 'fs';
export const fileExists = (path: string): boolean => {

View File

@@ -9,6 +9,7 @@ import './call/index.ts'
// import './hot-api/key-sender/index.ts';
import './opencode/index.ts';
import './remote/index.ts';
import './kevisual/index.ts'
import os from 'node:os';
import { authCache } from '@/module/cache/auth.ts';
@@ -160,6 +161,7 @@ app
})
.addTo(app);
// 调用 path: client key: system
app
.route({
path: 'client',

View File

@@ -0,0 +1,67 @@
import { app } from '@/app.ts'
import { runCmd } from '@/module/cmd/run.ts';
import { createSkill, tool } from "@kevisual/router";
import { useKey } from '@kevisual/use-config';
// 查看 ev cli 是否登录
app.route({
path: 'kevisual',
key: ' me',
description: '查看 ev cli 是否登录',
middleware: ['admin-auth'],
metadata: {
tags: ['opencode'],
...createSkill({
skill: 'kevisual-me',
title: '查看 ev cli 是否登录',
summary: '查看 ev cli 是否登录',
args: {
}
})
},
}).define(async (ctx) => {
const cmd = 'ev me';
const res = await runCmd({ cmd })
if (res.code === 200) {
ctx.body = { content: res.data };
} else {
ctx.throw(500, res.data);
}
}).addTo(app);
// 执行工具 kevisual-login-by-admin
// 执行工具 通过当前登录用户 ev cl
// 调用 path: kevisual key: loginByAdmin
app.route({
path: 'kevisual',
key: 'loginByAdmin',
description: '通过当前登录用户 ev cli',
middleware: ['admin-auth'],
metadata: {
tags: ['opencode'],
...createSkill({
skill: 'kevisual-login-by-admin',
title: '通过当前登录用户 ev cli',
summary: '通过当前登录用户登录 ev cli, 直接用当前的用户的 token 直接设置 token 给 ev cli, 登录失败直接停止任务',
args: {}
})
},
}).define(async (ctx) => {
const token = ctx.query?.token || useKey('KEVISUAL_TOKEN');
if (!token) {
ctx.throw(400, '登录的 token 不能为空,请传入 token 参数');
return;
}
const cmd = `ev login -e `;
const res = await runCmd({
cmd,
env: {
'KEVISUAL_TOKEN': token
}
})
if (res.code === 200) {
ctx.body = { content: res.data };
} else {
ctx.throw(500, res.data);
}
}).addTo(app);

View File

@@ -0,0 +1,45 @@
import { app } from '@/app.ts'
import { runCmd } from '@/module/cmd/run.ts';
import { createSkill, tool } from "@kevisual/router";
// 调用 path: kevisual key: deploy
app.route({
path: 'kevisual',
key: 'deploy',
description: '部署一个网页',
middleware: ['admin-auth'],
metadata: {
tags: ['kevisual'],
...createSkill({
skill: 'kevisual-deploy',
title: '部署一个网页',
summary: '部署一个网页到 kevisual 平台',
args: {
filepath: tool.schema.string().describe('要部署的网页文件路径'),
appKey: tool.schema.string().optional().describe('应用的 appKey如果不传则创建一个新的应用'),
version: tool.schema.string().optional().describe('应用的版本号,默认为 1.0.0'),
update: tool.schema.boolean().optional().describe('是否同时更新部署,默认为 false'),
}
})
},
}).define(async (ctx) => {
const { filepath, appKey, update } = ctx.query;
console.log('部署网页filepath:', filepath, 'appKey:', appKey);
ctx.body = { content: '部署功能正在开发中,敬请期待!' };
// ev deloly ${filepath} -k ${appKey} -v 1.0.0 -u -y y
// if (!filepath) {
// ctx.throw(400, '文件路径 filepath 不能为空');
// return;
// }
// let cmd = `ev deploy ${filepath} --type web`;
// if (appKey) {
// cmd += ` --appKey ${appKey}`;
// }
// const res = await runCmd({ cmd });
// if (res.code === 200) {
// ctx.body = { content: res.data };
// } else {
// ctx.throw(500, res.data);
// }
}).addTo(app);

View File

@@ -0,0 +1,2 @@
import './auth.ts'
import './deploy.ts'

View File

@@ -1,8 +1,6 @@
import { app } from '@/app.ts'
import { createSkill, tool } from "@kevisual/router";
import { opencodeManager } from './module/open.ts'
import path from "node:path";
import { execSync } from "node:child_process";
import { useKey } from '@kevisual/use-config';
// 创建一个opencode 客户端
@@ -27,7 +25,7 @@ app.route({
ctx.body = { content: `${opencodeManager.url} OpenCode 客户端已就绪` };
}).addTo(app);
// 关闭 opencode 客户端
// 关闭 opencode 客户端 5000
app.route({
path: 'opencode',
key: 'close',
@@ -38,17 +36,39 @@ app.route({
...createSkill({
skill: 'close-opencode-client',
title: '关闭 OpenCode 客户端',
summary: '关闭 OpenCode 客户端',
summary: '关闭 OpenCode 客户端, 未提供端口则关闭默认端口',
args: {
port: tool.schema.number().optional().describe('OpenCode 服务端口,默认为 5000')
}
})
},
}).define(async (ctx) => {
await opencodeManager.close();
const port = ctx.query.port;
await opencodeManager.close({ port });
ctx.body = { content: 'OpenCode 客户端已关闭' };
}).addTo(app);
app.route({
path: 'opencode',
key: 'restart',
middleware: ['auth'],
description: '重启 OpenCode 客户端',
metadata: {
tags: ['opencode'],
...createSkill({
skill: 'restart-opencode-client',
title: '重启 OpenCode 客户端',
summary: '重启 OpenCode 客户端',
args: {
port: tool.schema.number().optional().describe('OpenCode 服务端口,默认为 5000')
}
})
},
}).define(async (ctx) => {
const port = ctx.query.port;
const res = await opencodeManager.restart({ port });
ctx.body = { content: `${opencodeManager.url} OpenCode 客户端已经重启` };
}).addTo(app);
// 调用 path: opencode key: getUrl
app.route({
path: 'opencode',

View File

@@ -122,6 +122,11 @@ export class OpencodeManager {
}
return `http://localhost:${port}`;
}
async restart(opts?: { port?: number }): Promise<OpencodeClient> {
const port = opts?.port ?? DEFAULT_PORT;
await this.close({ port });
return await this.getClient({ port });
}
}
export const opencodeManager = OpencodeManager.getInstance();

273
pnpm-lock.yaml generated
View File

@@ -159,6 +159,9 @@ importers:
unstorage:
specifier: ^1.17.4
version: 1.17.4(idb-keyval@6.2.2)
zod:
specifier: ^4.3.6
version: 4.3.6
devDependencies:
'@kevisual/ai':
specifier: ^0.0.22
@@ -357,6 +360,121 @@ importers:
specifier: ^1.4.0
version: 1.4.0
cli-center-docs:
dependencies:
'@astrojs/mdx':
specifier: ^4.3.13
version: 4.3.13(astro@5.16.15(@types/node@25.0.10)(idb-keyval@6.2.2)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.43.0)(typescript@5.8.2))
'@astrojs/react':
specifier: ^4.4.2
version: 4.4.2(@types/node@25.0.10)(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
'@astrojs/sitemap':
specifier: ^3.7.0
version: 3.7.0
'@astrojs/vue':
specifier: ^5.1.4
version: 5.1.4(@types/node@25.0.10)(astro@5.16.15(@types/node@25.0.10)(idb-keyval@6.2.2)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.43.0)(typescript@5.8.2))(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.43.0)(vue@3.5.27(typescript@5.8.2))
'@kevisual/api':
specifier: ^0.0.28
version: 0.0.28
'@kevisual/context':
specifier: ^0.0.4
version: 0.0.4
'@kevisual/kv-code':
specifier: ^0.0.4
version: 0.0.4(@types/react@19.2.10)(dotenv@17.2.3)
'@kevisual/query':
specifier: ^0.0.38
version: 0.0.38
'@kevisual/query-login':
specifier: ^0.0.7
version: 0.0.7(@kevisual/query@0.0.38)
'@kevisual/registry':
specifier: ^0.0.1
version: 0.0.1(typescript@5.8.2)
'@radix-ui/react-slot':
specifier: ^1.2.4
version: 1.2.4(@types/react@19.2.10)(react@19.2.4)
'@tailwindcss/vite':
specifier: ^4.1.18
version: 4.1.18(vite@6.4.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2))
'@uiw/react-md-editor':
specifier: ^4.0.11
version: 4.0.11(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
antd:
specifier: ^6.2.2
version: 6.2.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
astro:
specifier: ^5.16.15
version: 5.16.15(@types/node@25.0.10)(idb-keyval@6.2.2)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.43.0)(typescript@5.8.2)
class-variance-authority:
specifier: ^0.7.1
version: 0.7.1
clsx:
specifier: ^2.1.1
version: 2.1.1
dayjs:
specifier: ^1.11.19
version: 1.11.19
es-toolkit:
specifier: ^1.44.0
version: 1.44.0
github-markdown-css:
specifier: ^5.8.1
version: 5.8.1
highlight.js:
specifier: ^11.11.1
version: 11.11.1
lucide-react:
specifier: ^0.563.0
version: 0.563.0(react@19.2.4)
marked:
specifier: ^17.0.1
version: 17.0.1
marked-highlight:
specifier: ^2.2.3
version: 2.2.3(marked@17.0.1)
nanoid:
specifier: ^5.1.6
version: 5.1.6
react:
specifier: ^19.2.4
version: 19.2.4
react-dom:
specifier: ^19.2.4
version: 19.2.4(react@19.2.4)
react-toastify:
specifier: ^11.0.5
version: 11.0.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
tailwind-merge:
specifier: ^3.4.0
version: 3.4.0
vue:
specifier: ^3.5.27
version: 3.5.27(typescript@5.8.2)
zustand:
specifier: ^5.0.10
version: 5.0.10(@types/react@19.2.10)(react@19.2.4)
devDependencies:
'@kevisual/types':
specifier: ^0.0.12
version: 0.0.12
'@types/react':
specifier: ^19.2.10
version: 19.2.10
'@types/react-dom':
specifier: ^19.2.3
version: 19.2.3(@types/react@19.2.10)
dotenv:
specifier: ^17.2.3
version: 17.2.3
tailwindcss:
specifier: ^4.1.18
version: 4.1.18
tw-animate-css:
specifier: ^1.4.0
version: 1.4.0
packages:
'@ant-design/colors@8.0.1':
@@ -1994,39 +2112,21 @@ packages:
'@sec-ant/readable-stream@0.4.1':
resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==}
'@shikijs/core@3.20.0':
resolution: {integrity: sha512-f2ED7HYV4JEk827mtMDwe/yQ25pRiXZmtHjWF8uzZKuKiEsJR7Ce1nuQ+HhV9FzDcbIo4ObBCD9GPTzNuy9S1g==}
'@shikijs/core@3.21.0':
resolution: {integrity: sha512-AXSQu/2n1UIQekY8euBJlvFYZIw0PHY63jUzGbrOma4wPxzznJXTXkri+QcHeBNaFxiiOljKxxJkVSoB3PjbyA==}
'@shikijs/engine-javascript@3.20.0':
resolution: {integrity: sha512-OFx8fHAZuk7I42Z9YAdZ95To6jDePQ9Rnfbw9uSRTSbBhYBp1kEOKv/3jOimcj3VRUKusDYM6DswLauwfhboLg==}
'@shikijs/engine-javascript@3.21.0':
resolution: {integrity: sha512-ATwv86xlbmfD9n9gKRiwuPpWgPENAWCLwYCGz9ugTJlsO2kOzhOkvoyV/UD+tJ0uT7YRyD530x6ugNSffmvIiQ==}
'@shikijs/engine-oniguruma@3.20.0':
resolution: {integrity: sha512-Yx3gy7xLzM0ZOjqoxciHjA7dAt5tyzJE3L4uQoM83agahy+PlW244XJSrmJRSBvGYELDhYXPacD4R/cauV5bzQ==}
'@shikijs/engine-oniguruma@3.21.0':
resolution: {integrity: sha512-OYknTCct6qiwpQDqDdf3iedRdzj6hFlOPv5hMvI+hkWfCKs5mlJ4TXziBG9nyabLwGulrUjHiCq3xCspSzErYQ==}
'@shikijs/langs@3.20.0':
resolution: {integrity: sha512-le+bssCxcSHrygCWuOrYJHvjus6zhQ2K7q/0mgjiffRbkhM4o1EWu2m+29l0yEsHDbWaWPNnDUTRVVBvBBeKaA==}
'@shikijs/langs@3.21.0':
resolution: {integrity: sha512-g6mn5m+Y6GBJ4wxmBYqalK9Sp0CFkUqfNzUy2pJglUginz6ZpWbaWjDB4fbQ/8SHzFjYbtU6Ddlp1pc+PPNDVA==}
'@shikijs/themes@3.20.0':
resolution: {integrity: sha512-U1NSU7Sl26Q7ErRvJUouArxfM2euWqq1xaSrbqMu2iqa+tSp0D1Yah8216sDYbdDHw4C8b75UpE65eWorm2erQ==}
'@shikijs/themes@3.21.0':
resolution: {integrity: sha512-BAE4cr9EDiZyYzwIHEk7JTBJ9CzlPuM4PchfcA5ao1dWXb25nv6hYsoDiBq2aZK9E3dlt3WB78uI96UESD+8Mw==}
'@shikijs/types@3.20.0':
resolution: {integrity: sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw==}
'@shikijs/types@3.21.0':
resolution: {integrity: sha512-zGrWOxZ0/+0ovPY7PvBU2gIS9tmhSUUt30jAcNV0Bq0gb2S98gwfjIs1vxlmH5zM7/4YxLamT6ChlqqAJmPPjA==}
@@ -2502,27 +2602,15 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
'@vue/compiler-core@3.5.26':
resolution: {integrity: sha512-vXyI5GMfuoBCnv5ucIT7jhHKl55Y477yxP6fc4eUswjP8FG3FFVFd41eNDArR+Uk3QKn2Z85NavjaxLxOC19/w==}
'@vue/compiler-core@3.5.27':
resolution: {integrity: sha512-gnSBQjZA+//qDZen+6a2EdHqJ68Z7uybrMf3SPjEGgG4dicklwDVmMC1AeIHxtLVPT7sn6sH1KOO+tS6gwOUeQ==}
'@vue/compiler-dom@3.5.26':
resolution: {integrity: sha512-y1Tcd3eXs834QjswshSilCBnKGeQjQXB6PqFn/1nxcQw4pmG42G8lwz+FZPAZAby6gZeHSt/8LMPfZ4Rb+Bd/A==}
'@vue/compiler-dom@3.5.27':
resolution: {integrity: sha512-oAFea8dZgCtVVVTEC7fv3T5CbZW9BxpFzGGxC79xakTr6ooeEqmRuvQydIiDAkglZEAd09LgVf1RoDnL54fu5w==}
'@vue/compiler-sfc@3.5.26':
resolution: {integrity: sha512-egp69qDTSEZcf4bGOSsprUr4xI73wfrY5oRs6GSgXFTiHrWj4Y3X5Ydtip9QMqiCMCPVwLglB9GBxXtTadJ3mA==}
'@vue/compiler-sfc@3.5.27':
resolution: {integrity: sha512-sHZu9QyDPeDmN/MRoshhggVOWE5WlGFStKFwu8G52swATgSny27hJRWteKDSUUzUH+wp+bmeNbhJnEAel/auUQ==}
'@vue/compiler-ssr@3.5.26':
resolution: {integrity: sha512-lZT9/Y0nSIRUPVvapFJEVDbEXruZh2IYHMk2zTtEgJSlP5gVOqeWXH54xDKAaFS4rTnDeDBQUYDtxKyoW9FwDw==}
'@vue/compiler-ssr@3.5.27':
resolution: {integrity: sha512-Sj7h+JHt512fV1cTxKlYhg7qxBvack+BGncSpH+8vnN+KN95iPIcqB5rsbblX40XorP+ilO7VIKlkuu3Xq2vjw==}
@@ -2551,9 +2639,6 @@ packages:
peerDependencies:
vue: 3.5.27
'@vue/shared@3.5.26':
resolution: {integrity: sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A==}
'@vue/shared@3.5.27':
resolution: {integrity: sha512-dXr/3CgqXsJkZ0n9F3I4elY8wM9jMJpP3pvRG52r6m0tu/MsAFIe6JpXVGeNMd/D9F4hQynWT8Rfuj0bdm9kFQ==}
@@ -4576,9 +4661,6 @@ packages:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'}
shiki@3.20.0:
resolution: {integrity: sha512-kgCOlsnyWb+p0WU+01RjkCH+eBVsjL1jOwUYWv0YDWkM2/A46+LDKVs5yZCUXjJG6bj4ndFoAg5iLIIue6dulg==}
shiki@3.21.0:
resolution: {integrity: sha512-N65B/3bqL/TI2crrXr+4UivctrAGEjmsib5rPMMPpFp1xAx/w03v8WZ9RDDFYteXoEgY7qZ4HGgl5KBIu1153w==}
@@ -4612,10 +4694,6 @@ packages:
resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==}
engines: {node: '>= 6.0.0', npm: '>= 3.0.0'}
smol-toml@1.5.2:
resolution: {integrity: sha512-QlaZEqcAH3/RtNyet1IPIYPsEWAaYyXXv1Krsi+1L/QHppjX4Ifm8MQsBISz9vE8cHicIq3clogsheili5vhaQ==}
engines: {node: '>= 18'}
smol-toml@1.6.0:
resolution: {integrity: sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==}
engines: {node: '>= 18'}
@@ -5152,6 +5230,9 @@ packages:
zod@4.1.8:
resolution: {integrity: sha512-5R1P+WwQqmmMIEACyzSvo4JXHY5WiAFHRMg+zBZKgKS+Q1viRa0C1hmUKtHltoIFKtIdki3pRxkmpP74jnNYHQ==}
zod@4.3.6:
resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
zustand@5.0.10:
resolution: {integrity: sha512-U1AiltS1O9hSy3rul+Ub82ut2fqIAefiSuwECWt6jlMVUGejvf+5omLcRBSzqbRagSM3hQZbtzdeRc6QVScXTg==}
engines: {node: '>=12.20.0'}
@@ -5243,8 +5324,8 @@ snapshots:
remark-parse: 11.0.0
remark-rehype: 11.1.2
remark-smartypants: 3.0.2
shiki: 3.20.0
smol-toml: 1.5.2
shiki: 3.21.0
smol-toml: 1.6.0
unified: 11.0.5
unist-util-remove-position: 5.0.0
unist-util-visit: 5.0.0
@@ -5321,7 +5402,7 @@ snapshots:
dependencies:
'@vitejs/plugin-vue': 5.2.4(vite@6.4.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2))(vue@3.5.27(typescript@5.8.2))
'@vitejs/plugin-vue-jsx': 4.2.0(vite@6.4.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2))(vue@3.5.27(typescript@5.8.2))
'@vue/compiler-sfc': 3.5.26
'@vue/compiler-sfc': 3.5.27
astro: 5.16.15(@types/node@25.0.10)(idb-keyval@6.2.2)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.43.0)(typescript@5.8.2)
vite: 6.4.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)
vite-plugin-vue-devtools: 7.7.9(rollup@4.43.0)(vite@6.4.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2))(vue@3.5.27(typescript@5.8.2))
@@ -6498,7 +6579,7 @@ snapshots:
'@jridgewell/gen-mapping@0.3.13':
dependencies:
'@jridgewell/sourcemap-codec': 1.5.0
'@jridgewell/sourcemap-codec': 1.5.5
'@jridgewell/trace-mapping': 0.3.31
'@jridgewell/remapping@2.3.5':
@@ -6515,7 +6596,7 @@ snapshots:
'@jridgewell/trace-mapping@0.3.31':
dependencies:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.0
'@jridgewell/sourcemap-codec': 1.5.5
'@kevisual/ai@0.0.19':
dependencies:
@@ -6686,7 +6767,7 @@ snapshots:
'@kevisual/router@0.0.36':
dependencies:
path-to-regexp: 8.3.0
selfsigned: 5.2.0
selfsigned: 5.4.0
send: 1.2.1(supports-color@10.2.2)
transitivePeerDependencies:
- supports-color
@@ -6960,7 +7041,7 @@ snapshots:
async: 2.6.4
debug: 4.3.7(supports-color@10.2.2)
eventemitter2: 6.4.9
extrareqp2: 1.0.0(debug@4.3.7(supports-color@10.2.2))
extrareqp2: 1.0.0(debug@4.3.7)
ws: 7.5.10
transitivePeerDependencies:
- bufferutil
@@ -7447,13 +7528,6 @@ snapshots:
'@sec-ant/readable-stream@0.4.1': {}
'@shikijs/core@3.20.0':
dependencies:
'@shikijs/types': 3.20.0
'@shikijs/vscode-textmate': 10.0.2
'@types/hast': 3.0.4
hast-util-to-html: 9.0.5
'@shikijs/core@3.21.0':
dependencies:
'@shikijs/types': 3.21.0
@@ -7461,49 +7535,25 @@ snapshots:
'@types/hast': 3.0.4
hast-util-to-html: 9.0.5
'@shikijs/engine-javascript@3.20.0':
dependencies:
'@shikijs/types': 3.20.0
'@shikijs/vscode-textmate': 10.0.2
oniguruma-to-es: 4.3.4
'@shikijs/engine-javascript@3.21.0':
dependencies:
'@shikijs/types': 3.21.0
'@shikijs/vscode-textmate': 10.0.2
oniguruma-to-es: 4.3.4
'@shikijs/engine-oniguruma@3.20.0':
dependencies:
'@shikijs/types': 3.20.0
'@shikijs/vscode-textmate': 10.0.2
'@shikijs/engine-oniguruma@3.21.0':
dependencies:
'@shikijs/types': 3.21.0
'@shikijs/vscode-textmate': 10.0.2
'@shikijs/langs@3.20.0':
dependencies:
'@shikijs/types': 3.20.0
'@shikijs/langs@3.21.0':
dependencies:
'@shikijs/types': 3.21.0
'@shikijs/themes@3.20.0':
dependencies:
'@shikijs/types': 3.20.0
'@shikijs/themes@3.21.0':
dependencies:
'@shikijs/types': 3.21.0
'@shikijs/types@3.20.0':
dependencies:
'@shikijs/vscode-textmate': 10.0.2
'@types/hast': 3.0.4
'@shikijs/types@3.21.0':
dependencies:
'@shikijs/vscode-textmate': 10.0.2
@@ -8108,7 +8158,7 @@ snapshots:
'@babel/types': 7.28.5
'@vue/babel-helper-vue-transform-on': 1.5.0
'@vue/babel-plugin-resolve-type': 1.5.0(@babel/core@7.28.5)
'@vue/shared': 3.5.26
'@vue/shared': 3.5.27
optionalDependencies:
'@babel/core': 7.28.5
transitivePeerDependencies:
@@ -8121,18 +8171,10 @@ snapshots:
'@babel/helper-module-imports': 7.27.1
'@babel/helper-plugin-utils': 7.27.1
'@babel/parser': 7.28.5
'@vue/compiler-sfc': 3.5.26
'@vue/compiler-sfc': 3.5.27
transitivePeerDependencies:
- supports-color
'@vue/compiler-core@3.5.26':
dependencies:
'@babel/parser': 7.28.5
'@vue/shared': 3.5.26
entities: 7.0.0
estree-walker: 2.0.2
source-map-js: 1.2.1
'@vue/compiler-core@3.5.27':
dependencies:
'@babel/parser': 7.28.5
@@ -8141,28 +8183,11 @@ snapshots:
estree-walker: 2.0.2
source-map-js: 1.2.1
'@vue/compiler-dom@3.5.26':
dependencies:
'@vue/compiler-core': 3.5.26
'@vue/shared': 3.5.26
'@vue/compiler-dom@3.5.27':
dependencies:
'@vue/compiler-core': 3.5.27
'@vue/shared': 3.5.27
'@vue/compiler-sfc@3.5.26':
dependencies:
'@babel/parser': 7.28.5
'@vue/compiler-core': 3.5.26
'@vue/compiler-dom': 3.5.26
'@vue/compiler-ssr': 3.5.26
'@vue/shared': 3.5.26
estree-walker: 2.0.2
magic-string: 0.30.21
postcss: 8.5.6
source-map-js: 1.2.1
'@vue/compiler-sfc@3.5.27':
dependencies:
'@babel/parser': 7.28.5
@@ -8175,11 +8200,6 @@ snapshots:
postcss: 8.5.6
source-map-js: 1.2.1
'@vue/compiler-ssr@3.5.26':
dependencies:
'@vue/compiler-dom': 3.5.26
'@vue/shared': 3.5.26
'@vue/compiler-ssr@3.5.27':
dependencies:
'@vue/compiler-dom': 3.5.27
@@ -8233,8 +8253,6 @@ snapshots:
'@vue/shared': 3.5.27
vue: 3.5.27(typescript@5.8.2)
'@vue/shared@3.5.26': {}
'@vue/shared@3.5.27': {}
acorn-jsx@5.3.2(acorn@8.15.0):
@@ -8986,9 +9004,9 @@ snapshots:
extend@3.0.2: {}
extrareqp2@1.0.0(debug@4.3.7(supports-color@10.2.2)):
extrareqp2@1.0.0(debug@4.3.7):
dependencies:
follow-redirects: 1.15.9(debug@4.3.7(supports-color@10.2.2))
follow-redirects: 1.15.9(debug@4.3.7)
transitivePeerDependencies:
- debug
@@ -9020,10 +9038,6 @@ snapshots:
optionalDependencies:
picomatch: 4.0.2
fdir@6.5.0(picomatch@4.0.2):
optionalDependencies:
picomatch: 4.0.2
fdir@6.5.0(picomatch@4.0.3):
optionalDependencies:
picomatch: 4.0.3
@@ -9042,7 +9056,7 @@ snapshots:
flattie@1.1.1: {}
follow-redirects@1.15.9(debug@4.3.7(supports-color@10.2.2)):
follow-redirects@1.15.9(debug@4.3.7):
optionalDependencies:
debug: 4.3.7(supports-color@10.2.2)
@@ -10862,17 +10876,6 @@ snapshots:
shebang-regex@3.0.0: {}
shiki@3.20.0:
dependencies:
'@shikijs/core': 3.20.0
'@shikijs/engine-javascript': 3.20.0
'@shikijs/engine-oniguruma': 3.20.0
'@shikijs/langs': 3.20.0
'@shikijs/themes': 3.20.0
'@shikijs/types': 3.20.0
'@shikijs/vscode-textmate': 10.0.2
'@types/hast': 3.0.4
shiki@3.21.0:
dependencies:
'@shikijs/core': 3.21.0
@@ -10913,8 +10916,6 @@ snapshots:
smart-buffer@4.2.0: {}
smol-toml@1.5.2: {}
smol-toml@1.6.0: {}
socks-proxy-agent@8.0.5(supports-color@10.2.2):
@@ -11257,7 +11258,7 @@ snapshots:
'@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.28.5)
'@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5)
'@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.28.5)
'@vue/compiler-dom': 3.5.26
'@vue/compiler-dom': 3.5.27
kolorist: 1.8.0
magic-string: 0.30.21
vite: 6.4.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2)
@@ -11267,8 +11268,8 @@ snapshots:
vite@6.4.1(@types/node@25.0.10)(jiti@2.6.1)(lightningcss@1.30.2):
dependencies:
esbuild: 0.25.12
fdir: 6.5.0(picomatch@4.0.2)
picomatch: 4.0.2
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
postcss: 8.5.6
rollup: 4.43.0
tinyglobby: 0.2.15
@@ -11365,6 +11366,8 @@ snapshots:
zod@4.1.8: {}
zod@4.3.6: {}
zustand@5.0.10(@types/react@19.2.10)(react@19.2.4):
optionalDependencies:
'@types/react': 19.2.10