diff --git a/assistant/package.json b/assistant/package.json index b7a2f54..7930f33 100644 --- a/assistant/package.json +++ b/assistant/package.json @@ -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" } } \ No newline at end of file diff --git a/assistant/src/module/assistant/config/index.ts b/assistant/src/module/assistant/config/index.ts index 41933aa..4eb816c 100644 --- a/assistant/src/module/assistant/config/index.ts +++ b/assistant/src/module/assistant/config/index.ts @@ -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; diff --git a/assistant/src/module/cmd/run.ts b/assistant/src/module/cmd/run.ts new file mode 100644 index 0000000..766e78c --- /dev/null +++ b/assistant/src/module/cmd/run.ts @@ -0,0 +1,49 @@ +import { spawn } from 'node:child_process' + +type RunCmdOptions = { + cmd: string; + cwd?: string; + env?: Record; +} + +type RunResult = { + code: number; + data: string; +} +/** + * 运行命令行指令 + * @param opts + * @returns + */ +export const runCmd = (opts: RunCmdOptions): Promise => { + const { cmd, cwd } = opts || {}; + return new Promise((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 }); + }); + }); +} \ 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 cd91a09..2534b4a 100644 --- a/assistant/src/module/light-code/run.ts +++ b/assistant/src/module/light-code/run.ts @@ -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 => { diff --git a/assistant/src/routes/index.ts b/assistant/src/routes/index.ts index 21e443c..6ceb7a4 100644 --- a/assistant/src/routes/index.ts +++ b/assistant/src/routes/index.ts @@ -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', diff --git a/assistant/src/routes/kevisual/auth.ts b/assistant/src/routes/kevisual/auth.ts new file mode 100644 index 0000000..b91f65c --- /dev/null +++ b/assistant/src/routes/kevisual/auth.ts @@ -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); \ No newline at end of file diff --git a/assistant/src/routes/kevisual/deploy.ts b/assistant/src/routes/kevisual/deploy.ts new file mode 100644 index 0000000..d25d963 --- /dev/null +++ b/assistant/src/routes/kevisual/deploy.ts @@ -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); \ No newline at end of file diff --git a/assistant/src/routes/kevisual/index.ts b/assistant/src/routes/kevisual/index.ts new file mode 100644 index 0000000..aaf4246 --- /dev/null +++ b/assistant/src/routes/kevisual/index.ts @@ -0,0 +1,2 @@ +import './auth.ts' +import './deploy.ts' \ No newline at end of file diff --git a/assistant/src/routes/opencode/ls.ts b/assistant/src/routes/opencode/ls.ts index 23632b9..0a9aded 100644 --- a/assistant/src/routes/opencode/ls.ts +++ b/assistant/src/routes/opencode/ls.ts @@ -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', diff --git a/assistant/src/routes/opencode/module/open.ts b/assistant/src/routes/opencode/module/open.ts index 87da2ab..2526807 100644 --- a/assistant/src/routes/opencode/module/open.ts +++ b/assistant/src/routes/opencode/module/open.ts @@ -122,6 +122,11 @@ export class OpencodeManager { } return `http://localhost:${port}`; } + async restart(opts?: { port?: number }): Promise { + const port = opts?.port ?? DEFAULT_PORT; + await this.close({ port }); + return await this.getClient({ port }); + } } export const opencodeManager = OpencodeManager.getInstance(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e4c9a72..bd59ec9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -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