Compare commits

...

37 Commits

Author SHA1 Message Date
xiongxiao
7582d8a6d3 udpate 2026-03-16 22:47:06 +08:00
xiongxiao
3971a428ff update 2026-03-16 22:24:58 +08:00
xiongxiao
f05bf93650 更新 check.ts 中的参数验证库为 zod,升级 package.json 版本并添加 zod 依赖 2026-03-16 22:23:54 +08:00
xiongxiao
95bcad7587 更新 .cnb.yml 中的命令行参数,修改 agent/npc.ts 以支持用户名称,更新 package.json 版本,完善 readme.md 环境变量说明 2026-03-16 22:20:39 +08:00
xiongxiao
c7a5200aa5 update 2026-03-16 22:02:20 +08:00
xiongxiao
296f893c22 up 2026-03-16 22:00:06 +08:00
xiongxiao
d019ee0158 update 2026-03-16 21:55:40 +08:00
xiongxiao
c7a0c6ac3c 更新 bun.config.ts 中 CLI 入口文件路径,升级依赖版本 2026-03-16 21:49:58 +08:00
xiongxiao
8813e06c61 更新 .cnb.yml,修复命令行工具依赖安装命令,使用 bun 替代 npm 2026-03-16 21:47:55 +08:00
xiongxiao
ae5565cda7 更新 NPC 相关逻辑,重构命令行工具,添加新的 CLI 入口,升级依赖版本 2026-03-16 21:45:37 +08:00
xiongxiao
fe89bdee5b update 2026-03-16 00:19:42 +08:00
a2702915d5 更新 openclaw URL 生成逻辑,修复 token 参数格式;升级依赖版本 2026-03-14 00:07:09 +08:00
xiongxiao
700e86a4d2 recover 2026-03-13 12:01:27 +08:00
xiongxiao
d9fda44e78 更新 CNB 配置获取逻辑,修复未授权问题,添加测试文件 2026-03-13 04:33:16 +08:00
xiongxiao
cda1d0dc8f test 2026-03-13 03:21:26 +08:00
xiongxiao
8249da006f update 2026-03-13 01:56:36 +08:00
xiongxiao
176c82f1ac 移除未使用的 cnb 导出,更新依赖版本,添加 opencode 客户端示例 2026-03-13 01:56:22 +08:00
xiongxiao
525f0af8ba 添加获取单个 Issue 的功能,更新相关类型和环境变量 2026-03-12 23:47:19 +08:00
2e630b2da9 udpate 2026-03-11 17:04:32 +08:00
79d82a1f8d update 2026-03-11 17:02:50 +08:00
f48568132a update 2026-03-11 16:55:36 +08:00
a551cbe79d update 2026-03-11 16:53:01 +08:00
xiongxiao
460979b577 update 2026-03-11 16:17:04 +08:00
xiongxiao
ef38fc0596 update 2026-03-11 16:15:48 +08:00
4e4f54b4cd update 2026-03-11 15:49:48 +08:00
07453f59df update 2026-03-11 15:46:51 +08:00
14719adbe7 update 2026-03-11 15:44:20 +08:00
3459066cd7 t 2026-03-11 15:40:37 +08:00
fc6a5bd73c test 2026-03-11 15:38:59 +08:00
8379be1630 temp 2026-03-11 15:15:29 +08:00
813005ab9c feat: 添加cnb智能对话接口,支持用户提问和消息列表处理 2026-03-11 15:15:29 +08:00
xiongxiao
38ee73e48f feat: update package version to 0.0.42 and add CNB version fetching functionality
- Updated package version in package.json from 0.0.40 to 0.0.42.
- Added getCNBVersion function to fetch CNB version information from the API.
- Enhanced Issue class with methods for managing comments (list, create, get, update).
- Introduced new NPC and comment environment hooks for better context management.
- Implemented Docker image synchronization route for CNB.
- Added tests for version fetching and issue comment functionalities.
2026-03-10 03:45:02 +08:00
7b8f6fbf9f update 2026-03-10 01:18:52 +08:00
d08345d81c feat: 添加云端构建功能,支持参数配置和环境变量 2026-03-10 01:18:27 +08:00
xiongxiao
7d227d3913 feat: 更新获取CNB配置的路由,优化参数处理并添加错误处理 2026-03-09 19:13:20 +08:00
xiongxiao
a40c2352bf chore: 更新版本号至0.0.38 2026-03-09 18:56:56 +08:00
xiongxiao
382c4809ea feat: 重构CNB管理模块,添加清理记录功能,更新中间件为统一认证方式,优化工作空间相关路由 2026-03-09 18:54:33 +08:00
55 changed files with 2233 additions and 252 deletions

View File

@@ -8,6 +8,18 @@ include:
imports:
- https://cnb.cool/kevisual/env/-/blob/main/.env.development
.npc: &npc
- docker:
image: docker.cnb.cool/kevisual/dev-env/ubuntu-bun:latest
services:
- docker
env: !reference [.common_env, env]
imports: !reference [.common_env, imports]
stages:
- name: "task"
script: |
git clone https://cnb.cool/kevisual/cnb cnb
cd cnb && bun i && bun run agent/npc.ts cnb npc --args owner="小熊猫呜呜呜"
$:
vscode:
- docker:
@@ -17,4 +29,7 @@ $:
- docker
env: !reference [.common_env, env]
imports: !reference [.common_env, imports]
stages: !reference [.dev_template, stages]
issue.comment@npc: *npc
issue.open: *npc
issue.reopen: *npc

6
.cnb/settings.yml Normal file
View File

@@ -0,0 +1,6 @@
npc:
defaultRole: router
roles:
- name: router
prompt: |
你好

1
.gitignore vendored
View File

@@ -4,5 +4,6 @@ node_modules
.pnpm-store
dist
pack-dist
storage

1
.npmrc
View File

@@ -1,3 +1,2 @@
//npm.xiongxiao.me/:_authToken=${ME_NPM_TOKEN}
//npm.cnb.cool/kevisual/registry/-/packages/:_authToken=${CNB_API_KEY}
//registry.npmjs.org/:_authToken=${NPM_TOKEN}

View File

@@ -1,5 +1,5 @@
{
"dependencies": {
"@opencode-ai/plugin": "1.2.9"
"@opencode-ai/plugin": "1.2.26"
}
}

16
SKILL.md Normal file
View File

@@ -0,0 +1,16 @@
---
name: 'cloud-cnb'
description: cloud-cnb 是一个基于 cnb.cool 的自动化工具,提供了工作区管理、代码仓库创建和 kevisual assistant app 等功能,旨在提升开发效率和项目管理的便捷性。
---
# 执行命令
```sh
## help
cloud -h
```
## 运行查看cli列表
```sh
cloud cli list
```

View File

@@ -1,17 +1,35 @@
import { QueryRouterServer as App } from '@kevisual/router'
import { useContextKey } from '@kevisual/context'
import { useConfig, useKey } from '@kevisual/use-config'
import { useKey } from '@kevisual/use-config'
import { CNB } from '../src/index.ts';
import { CNBManager } from './modules/cnb-manager.ts'
export const config = useConfig()
export const cnb = useContextKey<CNB>('cnb', () => {
// CNB_TOKEN是降级兼容变量推荐使用CNB_API_KEY
// CNB_TOKEN 是流水线自己就有的变量,但是权限比较小
const token = useKey('CNB_API_KEY') as string || useKey('CNB_TOKEN') as string
// cookie 变量是可选的
const cookie = useKey('CNB_COOKIE') as string
return new CNB({ token: token, cookie: cookie });
})
export const app = useContextKey<App>('app', () => {
export const cnbManager = new CNBManager()
// CNB_TOKEN是降级兼容变量推荐使用CNB_API_KEY
// CNB_TOKEN 是流水线自己就有的变量,但是权限比较小
const token = useKey('CNB_API_KEY') as string || useKey('CNB_TOKEN') as string
// cookie 变量是可选的
const cookie = useKey('CNB_COOKIE') as string
try {
cnbManager.addCNB({
username: 'default',
token: token,
cookie: cookie,
cnb: new CNB({ token: token, cookie: cookie })
})
} catch (error) {
process.exit(1)
}
await new Promise(resolve => setTimeout(resolve, 1000))
export const app = await useContextKey<App>('app', () => {
return new App({})
})
})
export const notCNBCheck = (ctx: any) => {
const isCNB = useKey('CNB');
if (!isCNB) {
ctx.throw(400, '当前环境非 cnb-board 环境,无法获取内容');
}
return false;
}

View File

@@ -1,4 +1,4 @@
import { app } from './index.ts';
import { parse } from '@kevisual/router/src/commander.ts';
parse({ app: app as any, description: 'CNB控制台命令行工具', parse: true })
parse({ app: app, description: 'CNB控制台命令行工具', parse: true })

18
agent/main.ts Normal file
View File

@@ -0,0 +1,18 @@
// import { RemoteApp } from '@kevisual/remote-app';
import { app } from './index.ts'
// import { QueryLoginNode } from '@kevisual/api/login-node';
// const queryLoginNode = new QueryLoginNode({});
// await queryLoginNode.init()
// const token = await queryLoginNode.getToken();
// app.createRouteList()
// const remoteApp = new RemoteApp({
// id: 'cnb-agent',
// token: token,
// url: 'https://kevisual.cn/ws/proxy',
// app: app as any,
// })
// const isConnected = await remoteApp.isConnect();
// if (isConnected) {
// console.log('Remote app connected successfully');
// remoteApp.listenProxy();
// }

View File

@@ -0,0 +1,141 @@
import { Result } from '@kevisual/query';
import { CNB } from '../../src/index.ts';
import { useKey } from '@kevisual/context';
import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
export const getConfig = async (opts: { token?: string }) => {
const kevisualEnv = useKey('KEVISUAL_ENV')
const isCNB = useKey('CNB');
let isProduction = kevisualEnv !== 'development' || (isCNB && !kevisualEnv);
const baseUrl = isProduction ? 'https://kevisual.cn/api/router' : 'https://kevisual.xiongxiao.me/api/router';
const res = await fetch(baseUrl, {
method: 'POST',
body: JSON.stringify({
path: 'config',
key: 'get',
data: {
key: "cnb_center_config.json"
}
}),
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${opts.token!}`
},
}).then(res => res.json());
return res as Result<{
id: string, key: 'cnb_center_config.json', data: {
CNB_API_KEY: string,
CNB_COOKIE: string
}
}>;
}
type CNBItem = {
username: string,
token: string,
cookie?: string
runAt?: number
owner?: boolean
cnb: CNB
cnbAi: ReturnType<typeof createOpenAICompatible>
}
// const repo = useKey('CNB_REPO_SLUG_LOWERCASE') as string || 'kevision/kevision';
// export const cnbAi = createOpenAICompatible({
// baseURL: `https://api.cnb.cool/${repo}/-/ai/`,
// name: 'custom-cnb',
// apiKey: token,
// });
export class CNBManager {
cnbMap: Map<string, CNBItem> = new Map()
constructor() {
setInterval(() => {
this.clearExpiredCNB()
}, 1000 * 60 * 30) // 每30分钟清理一次过期的 CNB 实例
}
getDefaultCNB() {
const cnbItem = this.cnbMap.get('default')
if (!cnbItem) {
throw new Error('Default CNB not found')
}
return cnbItem
}
async getCNB(opts?: { username?: string, kevisualToken?: string }): Promise<CNBItem | null> {
const username = opts?.username
const cnbItem = this.cnbMap.get(username)
if (cnbItem) {
cnbItem.runAt = Date.now()
return cnbItem
}
const res = await getConfig({ token: opts?.kevisualToken })
if (res.code === 200) {
const cookie = res.data?.data?.CNB_COOKIE
const token = res.data?.data?.CNB_API_KEY
if (token) {
return this.addCNB({ username, token, cookie })
}
} else {
console.error('获取 CNB 配置失败', username, res)
}
return null
}
/**
* 通过上下文获取 CNB 实例(直接返回 cnb 对象)
* @param ctx
* @returns CNB 实例
*/
async getContext(ctx: any) {
const item = await this.getCNBItem(ctx)
return item.cnb
}
async getCNBItem(ctx: any) {
const tokenUser = ctx?.state?.tokenUser
const username = tokenUser?.username
if (!username) {
ctx.throw(403, 'Unauthorized')
}
if (username === 'default') {
return this.getDefaultCNB()
}
const kevisualToken = ctx.query?.token;
const item = await this.getCNB({ username, kevisualToken });
if (!item) {
ctx.throw(400, '不存在的 CNB 配置项,请检查 登录 Token 是否正确,或添加 CNB 配置')
}
return item;
}
addCNB(opts: Partial<CNBItem>) {
if (!opts.username || !opts.token) {
throw new Error('username and token are required')
}
const exist = this.cnbMap.get(opts.username)
if (exist) {
exist.runAt = Date.now()
return exist
}
const cnb = opts?.cnb || new CNB({ token: opts.token, cookie: opts.cookie });
opts.cnb = cnb;
opts.runAt = Date.now()
const repoSlug = useKey('CNB_REPO_SLUG_LOWERCASE') as string || 'kevision/kevision';
opts.cnbAi = createOpenAICompatible({
baseURL: `https://api.cnb.cool/${repoSlug}/-/ai/`,
name: `custom-cnb-${opts.username}`,
apiKey: opts.token,
})
this.cnbMap.set(opts.username, opts as CNBItem)
return opts as CNBItem
}
// 定期清理过期的 CNB 实例,默认过期时间为 1 小时
clearExpiredCNB(expireTime = 1000 * 60 * 60) {
const now = Date.now()
for (const [username, item] of this.cnbMap.entries()) {
if (username === 'default') {
continue
}
if (item.runAt && now - item.runAt > expireTime) {
this.cnbMap.delete(username)
}
}
}
clearUsername(username: string) {
this.cnbMap.delete(username)
}
}

125
agent/npc.ts Normal file
View File

@@ -0,0 +1,125 @@
import { app } from './index.ts';
import { parse } from '@kevisual/router/src/commander.ts';
import { useIssueEnv, useCommentEnv, useRepoInfoEnv, IssueLabel } from '../src/index.ts'
import { pick } from 'es-toolkit';
import z from 'zod';
import { useKey } from '@kevisual/context';
const writeToProcess = (message: string) => {
if (process.send) {
process.send(message);
} else {
console.log(message);
}
}
const getIssuesLabels = async () => {
const issueEnv = useIssueEnv();
const repoInfoEnv = useRepoInfoEnv();
const issueId = issueEnv.issueId;
const repoSlug = repoInfoEnv.repoSlug;
if (!issueId || !repoSlug) {
return [];
}
const res = await app.run({
path: 'cnb',
key: 'getIssue',
payload: {
repo: repoSlug,
issueNumber: issueId
}
});
if (res.code === 200) {
const issueData = res.data as any;
const labels = issueData.labels || [];
return labels as IssueLabel[];
}
console.error('获取 Issue 详情失败', res);
return []
}
const main = async ({ exit, question }: { exit: (code: number) => void, question?: string }) => {
const repoInfoEnv = useRepoInfoEnv();
const commentEnv = useCommentEnv();
const issueEnv = useIssueEnv();
const pickCommentEnv = pick(commentEnv, ['commentId', 'commentIdLabel']);
const pickIssueEnv = pick(issueEnv, ['issueId', 'issueIdLabel', 'issueIid', 'issueIidLabel', 'issueTitle', 'issueTitleLabel', 'issueDescription', 'issueDescriptionLabel']);
const pickRepoInfoEnv = pick(repoInfoEnv, ['repoId', 'repoIdLabel', 'repoName', 'repoNameLabel', 'repoSlug', 'repoSlugLabel']);
// const issueLabels = issueEnv.issueLabels || [];
const isComment = !!commentEnv.commentId;
const envList = [
...Object.entries(pickRepoInfoEnv).map(([key, value]) => `${key}: ${value}`),
...Object.entries(issueEnv).map(([key, value]) => `${key}: ${value}`),
...Object.entries(pickCommentEnv).map(([key, value]) => `${key}: ${value}`),
]
writeToProcess('当前环境变量:');
const issueLabels = await getIssuesLabels();
const issueLabelsNames = issueLabels.map(label => label.name) || [];
envList.forEach(item => writeToProcess(item));
if (!isComment && !issueLabelsNames.includes('Run')) {
writeToProcess('当前 Issue 不包含 Run 标签,跳过执行');
return exit(0);
}
const messages = [
{
role: 'system',
content: `你是一个智能的代码助手, 根据用户提供的上下文信息,提供有用的建议和帮助, 如果用户的要求和执行工具不一致请说出你不能这么做。并把最后的结果提交一个评论到对应的issue中,提交的内容必须不能包含 @ 提及。用户提供的上下文信息如下:`
},
{
role: 'system',
content: `相关变量:${JSON.stringify({ ...pickCommentEnv, ...pickIssueEnv, ...pickRepoInfoEnv })}`
}, {
role: 'user',
content: question || commentEnv.commentBody || pickIssueEnv.issueDescription || '无'
}
]
writeToProcess('输入消息:');
writeToProcess(JSON.stringify(messages, null, 2));
const result = await app.run({
path: 'cnb',
key: 'chat',
payload: {
messages
}
}, { appId: app.appId })
if (result.code === 200) {
let _message = result.data.message || []
writeToProcess('执行完成')
writeToProcess(JSON.stringify(_message, null, 2))
exit(0);
} else {
writeToProcess(result.message || '执行错误')
exit(1);
}
}
app.route({
path: 'cnb',
key: 'npc',
description: 'CNB智能助手,提供智能建议和帮助, 程序入口',
metadata: {
tags: ['notInNpcAgent'],
args: {
needExit: z.boolean().optional().describe('是否需要在执行完成后退出进程'),
owner: z.string().optional().describe('用户名称')
}
}
}).define(async (ctx) => {
const needExit = ctx.args.needExit ?? true;
const owner = ctx.args.owner || '';
const exit = (code: number) => {
if (needExit) {
process.exit(code);
}
}
const buildUserNickName = useKey('CNB_BUILD_USER_NICKNAME')
let admins = owner.split(',').map(item => item.trim());
if (owner && admins.includes(buildUserNickName)) {
await main({ exit });
} else {
await main({ exit, question: `你是${owner}的专属助手请生成一条评论说明你不具备其他用户能访问的能力。同时你需要提示说明fork当前仓库后即可成为你的专属助手` });
}
}).addTo(app)
parse({ app: app, description: 'CNB控制台命令行工具', parse: true })

View File

@@ -2,5 +2,5 @@ import { app } from './index.ts';
import { createRouterAgentPluginFn } from '@kevisual/router/opencode'
export const CnbPlugin = createRouterAgentPluginFn({
router: app,
router: app as any,
})

View File

@@ -0,0 +1,66 @@
import { execSync } from 'child_process';
import { app, notCNBCheck } from '../../app.ts'
import { z } from 'zod'
import { title } from 'process';
app.route({
path: 'cnb',
key: 'docker-sync',
middleware: ['auth'],
metadata: {
tag: ['opencode'],
skill: 'cnb-docker-sync',
title: 'CNB Docker 镜像同步',
args: {
image: z.string().describe('Docker 同步的具体的镜像名称.'),
toVersion: z.string().optional().describe('修改后的版本号.'),
}
}
}).define(async (ctx) => {
const { image, toVersion } = ctx.args;
notCNBCheck(ctx);
if (!image) {
ctx.body = {
message: '请提供 Docker 镜像名称.',
data: null,
}
return;
}
const config = {
registry: 'docker.cnb.cool/kevisual/dev-env',
dockers: [{ image, toVersion }]
}
// docker tag ghcr.io/esm-dev/esm.sh:v137 docker.cnb.cool/kevisual/dev-env/esm.sh:v137
// docker push docker.cnb.cool/kevisual/dev-env/esm.sh:v137
const run = async () => {
const dockers = config.dockers;
for (const { image, toVersion } of dockers) {
const imageName = image.split(':')[0].split('/').slice(-1)[0]
const tag = image.split(':')[1]
const newImage = `${config.registry}/${imageName}:${toVersion || tag}`
// console.log(`docker tag ${image} ${newImage}`)
// console.log(`docker push ${newImage}`)
const shell = `docker pull ${image} && docker tag ${image} ${newImage} && docker push ${newImage}`
console.log(shell)
console.log('\n-------------new---------------------------------\n')
console.log(`${newImage}`)
console.log('\n--------------------------------------------------\n')
try {
execSync(shell, { stdio: 'inherit' })
} catch (error) {
console.error(`Error: ${error}`)
}
}
}
run().then(() => {
// TODO: 通知用户同步完成
});;
ctx.body = {
message: 'Docker 镜像同步任务中,请稍后在目标仓库查看.',
data: {
registry: config.registry,
dockers: config.dockers,
}
}
}).addTo(app);

View File

@@ -0,0 +1 @@
import './docker.ts'

49
agent/routes/chat/chat.ts Normal file
View File

@@ -0,0 +1,49 @@
import { runAgent } from '@kevisual/ai/agent'
import { app, cnbManager } from '../../app.ts';
import z from 'zod';
app.route({
path: 'cnb',
key: 'chat',
description: 'cnb智能对话接口',
middleware: ['auth'],
metadata: {
args: {
question: z.string().describe('用户输入的问题'),
messages: z.array(z.object({
role: z.enum(['user', 'assistant']).describe('消息角色user表示用户输入assistant表示助手回复'),
content: z.string().describe('消息内容')
})).describe('对话消息列表,按照时间顺序排列,包含用户和助手的历史消息'),
model: z.string().optional().describe('默认auto')
}
}
}).define(async (ctx) => {
// notCNBCheck(ctx);
if (!ctx.args.question && !ctx.args.messages) {
ctx.throw(400, '缺少必要参数必须提供question或messages');
return;
}
const model = ctx.args?.model || 'auto'
const item = await cnbManager.getCNBItem(ctx);
const cnbAi = item.cnbAi;
const messages = ctx.args.messages || [{
role: 'user',
content: ctx.args.question
}]
const routes = app.routes.filter(route => {
const tags = route.metadata?.tags || [];
if (tags.includes('notInNpcAgent')) {
return false;
}
return true
});
const result = await runAgent({
app,
messages: messages,
routes,
languageModel: cnbAi(model),
token: '',
// token: ctx.query.token as string,
});
ctx.body = result;
}).addTo(app);

View File

@@ -1,23 +1,13 @@
import { app } from '../../app.ts';
import { app, notCNBCheck } from '../../app.ts';
import { useKey } from '@kevisual/context'
import { getLiveMdContent } from './live/live-content.ts';
import z from 'zod';
const notCNBCheck = (ctx: any) => {
const isCNB = useKey('CNB');
if (!isCNB) {
ctx.body = {
title: '非 cnb-board 环境',
list: []
}
return true;
}
return false;
}
app.route({
path: 'cnb_board',
key: 'live',
description: '获取cnb-board live的mdContent内容',
middleware: ['auth-admin'],
middleware: ['auth'],
metadata: {
args: {
more: z.boolean().optional().describe('是否获取更多系统信息默认false'),
@@ -37,7 +27,7 @@ app.route({
path: 'cnb_board',
key: 'live_repo_info',
description: '获取cnb-board live的repo信息',
middleware: ['auth-admin']
middleware: ['auth']
}).define(async (ctx) => {
const repoSlug = useKey('CNB_REPO_SLUG') || '';
const repoName = useKey('CNB_REPO_NAME') || '';
@@ -90,7 +80,7 @@ app.route({
path: 'cnb_board',
key: 'live_build_info',
description: '获取cnb-board live的构建信息',
middleware: ['auth-admin']
middleware: ['auth']
}).define(async (ctx) => {
if (notCNBCheck(ctx)) return;
const labels = [

View File

@@ -1,4 +1,4 @@
import { app } from '../../app.ts';
import { app, notCNBCheck } from '../../app.ts';
import './cnb-dev-env.ts';
import { useKey } from '@kevisual/context';
import { spawnSync } from 'node:child_process';
@@ -31,8 +31,9 @@ app.route({
path: 'cnb_board',
key: 'exit',
description: 'cnb的工作环境退出程序',
middleware: ['auth-admin'],
middleware: ['auth'],
}).define(async (ctx) => {
if (notCNBCheck(ctx)) return;
const cmd = 'kill 1';
execCommand(cmd);
}).addTo(app);

View File

@@ -10,7 +10,7 @@ export const getLiveMdContent = (opts?: { more?: boolean }) => {
const token = useKey('CNB_TOKEN') || ''
const openclawPort = useKey('OPENCLAW_PORT') || '80'
const openclawUrl = url.replace('{{port}}', openclawPort)
const openclawUrlSecret = openclawUrl + '/openclaw?token=' + token
const openclawUrlSecret = openclawUrl + '/openclaw#token=' + token
const opencodePort = useKey('OPENCODE_PORT') || '100'
const opencodeUrl = url.replace('{{port}}', opencodePort)

View File

@@ -1,13 +1,13 @@
import { createSkill } from '@kevisual/router';
import { app, cnb } from '../../app.ts';
import { tool } from '@opencode-ai/plugin/tool';
import { app, cnbManager } from '../../app.ts';
import { z } from 'zod';
app.route({
path: 'cnb',
key: 'user-check',
description: '检查用户登录状态参数checkToken,default true; checkCookie, default false',
middleware: ['auth-admin'],
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
@@ -15,8 +15,8 @@ app.route({
title: 'CNB 登录验证信息',
summary: '验证 CNB 登录信息是否有效',
args: {
checkToken: tool.schema.boolean().describe('是否检查 Token 的有效性').default(true),
checkCookie: tool.schema.boolean().describe('是否检查 Cookie 的有效性').default(false),
checkToken: z.boolean().describe('是否检查 Token 的有效性').default(true),
checkCookie: z.boolean().describe('是否检查 Cookie 的有效性').default(false),
},
})
}
@@ -24,6 +24,7 @@ app.route({
const checkToken = ctx.query?.checkToken ?? true;
const checkCookie = ctx.query?.checkCookie ?? false;
let content = '';
const cnb = await cnbManager.getContext(ctx);
if (checkToken) {
const res = await cnb.user.getUser();
if (res?.code !== 200) {

View File

@@ -1,12 +1,12 @@
import { createSkill, tool } from '@kevisual/router';
import { app, cnb } from '../../app.ts';
import { app, cnbManager } from '../../app.ts';
// 设置 CNB_COOKIE环境变量和获取环境变量,用于界面操作定制模块功能
app.route({
path: 'cnb',
key: 'set-cnb-cookie',
description: '设置当前cnb工作空间的cookie环境变量',
middleware: ['auth-admin'],
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
@@ -19,6 +19,7 @@ app.route({
})
}
}).define(async (ctx) => {
const cnb = await cnbManager.getContext(ctx);
const cookie = ctx.query?.cookie;
if (!cookie) {
ctx.body = { content: '请提供有效的cookie值' };
@@ -33,7 +34,7 @@ app.route({
path: 'cnb',
key: 'get-cnb-cookie',
description: '获取当前cnb工作空间的cookie环境变量',
middleware: ['auth-admin'],
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
@@ -43,6 +44,7 @@ app.route({
})
}
}).define(async (ctx) => {
const cnb = await cnbManager.getContext(ctx);
const cookie = cnb.cookie || '未设置cookie环境变量';
ctx.body = { content: `当前cnb工作空间的cookie环境变量为${cookie}` };
}).addTo(app);

View File

@@ -1,5 +1,5 @@
import { createSkill, tool } from '@kevisual/router';
import { app, cnb } from '../../app.ts';
import { app, notCNBCheck } from '../../app.ts';
import { CNB_ENV } from "@/common/cnb-env.ts";
@@ -11,7 +11,7 @@ app.route({
path: 'cnb',
key: 'get-cnb-port-uri',
description: '获取当前cnb工作空间的port代理uri',
middleware: ['auth-admin'],
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
@@ -24,6 +24,7 @@ app.route({
})
}
}).define(async (ctx) => {
if (notCNBCheck(ctx)) return;
const port = ctx.query?.port || 51515;
const uri = CNB_ENV?.CNB_VSCODE_PROXY_URI as string || '';
const finalUri = uri.replace('{{port}}', port.toString());
@@ -40,7 +41,7 @@ app.route({
path: 'cnb',
key: 'get-cnb-vscode-uri',
description: '获取当前cnb工作空间的vscode代理uri, 包括多种访问方式, 如web、vscode、codebuddy、cursor、ssh',
middleware: ['auth-admin'],
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
@@ -58,6 +59,7 @@ app.route({
})
}
}).define(async (ctx) => {
if (notCNBCheck(ctx)) return;
const web = ctx.query?.web ?? false;
const vscode = ctx.query?.vscode ?? true; // 默认true
const codebuddy = ctx.query?.codebuddy ?? false;

View File

@@ -0,0 +1,49 @@
import { app, cnbManager } from '../../app.ts';
// "列出我的代码仓库search blog"
// 列出我的知识库的代码仓库
app.route({
path: 'cnb',
key: 'clear-me-manager',
description: '清理我的cnb-manager记录',
middleware: ['auth'],
}).define(async (ctx) => {
const tokenUser = ctx.state?.tokenUser;
if (!tokenUser) {
ctx.throw(401, '未授权');
}
const username = tokenUser.username;
if (!username) {
ctx.throw(400, '无效的用户信息');
}
if (username !== 'default') {
cnbManager.clearUsername(username);
}
ctx.body = { content: '已清理cnb-manager记录' };
}).addTo(app);
app.route({
path: 'cnb',
key: 'get-my-config',
description: '获取我的cnb配置',
middleware: ['auth'],
}).define(async (ctx) => {
const tokenUser = ctx.state?.tokenUser;
const username = tokenUser?.username;
const token = ctx.query?.token;
if (!username) {
ctx.throw(400, '未授权');
}
if (!token) {
ctx.throw(400, '缺少token参数');
}
const cnbItem = await cnbManager.getCNB({ username, kevisualToken: token });
if (!cnbItem) {
ctx.throw(404, '未找到cnb-manager记录');
}
ctx.body = {
token: cnbItem.token,
cookie: cnbItem.cookie,
}
}).addTo(app);

View File

@@ -0,0 +1,6 @@
const token = 'st_logh1b3ozq2resntxlnk4bccao0bon8e'
import { CNBManager } from "../../modules/cnb-manager.ts"
const cnbManager = new CNBManager()
const cnbItem = await cnbManager.getCNB({ username: 'root', kevisualToken: token });
console.log('cnbItem', cnbItem)

View File

@@ -8,6 +8,10 @@ import './knowledge/index.ts'
import './issues/index.ts'
import './cnb-board/index.ts';
import './share/index.ts';
import './cnb-manager/index.ts';
import './build/index.ts';
import './chat/chat.ts';
/**
* 验证上下文中的 App ID 是否与指定的 App ID 匹配
* @param {any} ctx - 上下文对象,可能包含 appId 属性
@@ -32,6 +36,9 @@ app.route({
}).define(async (ctx) => {
// ctx.body = 'Auth Route';
if (checkAppId(ctx, app.appId)) {
ctx.state.tokenUser = {
username: 'default',
}
return;
}
}).addTo(app, { overwrite: false });
@@ -43,6 +50,9 @@ app.route({
}).define(async (ctx) => {
// ctx.body = 'Admin Auth Route';
if (checkAppId(ctx, app.appId)) {
ctx.state.tokenUser = {
username: 'default',
}
return;
}
}).addTo(app, { overwrite: false });

View File

@@ -0,0 +1,177 @@
import { createSkill, tool } from '@kevisual/router';
import { app, cnbManager } from '../../app.ts';
import { useKey } from '@kevisual/context';
// 查询 Issue 评论列表
app.route({
path: 'cnb',
key: 'list-issue-comments',
description: '查询 Issue 评论列表, 参数 repo, issueNumber, page, page_size',
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
skill: 'list-issue-comments',
title: '查询 Issue 评论列表',
args: {
repo: tool.schema.string().optional().describe('代码仓库名称, 如 my-user/my-repo'),
issueNumber: tool.schema.number().describe('Issue 编号'),
page: tool.schema.number().optional().describe('分页页码,默认: 1'),
page_size: tool.schema.number().optional().describe('分页每页大小,默认: 30'),
},
summary: '查询 Issue 评论列表',
})
}
}).define(async (ctx) => {
const cnb = await cnbManager.getContext(ctx);
let repo = ctx.query?.repo || useKey('CNB_REPO_SLUG_LOWERCASE');
const issueNumber = ctx.query?.issueNumber;
const page = ctx.query?.page ? Number(ctx.query.page) : undefined;
const page_size = ctx.query?.page_size ? Number(ctx.query.page_size) : undefined;
if (!repo) {
ctx.throw(400, '缺少参数 repo');
}
if (!issueNumber) {
ctx.throw(400, '缺少参数 issueNumber');
}
const params: Record<string, any> = {};
if (page) params.page = page;
if (page_size) params.page_size = page_size;
const res = await cnb.issue.getCommentList(repo, issueNumber, params);
ctx.forward(res);
}).addTo(app);
// 创建 Issue 评论
app.route({
path: 'cnb',
key: 'create-issue-comment',
description: '创建 Issue 评论, 参数 repo, issueNumber, body',
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
skill: 'create-issue-comment',
title: '创建 Issue 评论',
args: {
repo: tool.schema.string().optional().describe('代码仓库名称, 如 my-user/my-repo'),
issueNumber: tool.schema.number().describe('Issue 编号'),
body: tool.schema.string().describe('评论内容'),
clearAt: tool.schema.boolean().optional().describe('是否清除评论内容中的 @ 提及,默认: true'),
},
summary: '创建 Issue 评论',
})
}
}).define(async (ctx) => {
const cnb = await cnbManager.getContext(ctx);
let repo = ctx.query?.repo || useKey('CNB_REPO_SLUG_LOWERCASE');
const issueNumber = ctx.query?.issueNumber;
let body = ctx.query?.body;
const clearAt = ctx.query?.clearAt ?? true;
if (!repo) {
ctx.throw(400, '缺少参数 repo');
}
if (!issueNumber) {
ctx.throw(400, '缺少参数 issueNumber');
}
if (!body) {
ctx.throw(400, '缺少参数 body');
}
if (clearAt && body) {
// 清除评论内容中的 @ 提及
body = body.replace(/@/g, '');
}
const res = await cnb.issue.createComment(repo, issueNumber, body);
ctx.forward(res);
}).addTo(app);
// 获取 Issue 指定评论
app.route({
path: 'cnb',
key: 'get-issue-comment',
description: '获取 Issue 指定评论, 参数 repo, issueNumber, commentId',
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
skill: 'get-issue-comment',
title: '获取 Issue 评论',
args: {
repo: tool.schema.string().optional().describe('代码仓库名称, 如 my-user/my-repo'),
issueNumber: tool.schema.number().describe('Issue 编号'),
commentId: tool.schema.number().describe('评论 ID'),
},
summary: '获取 Issue 评论',
})
}
}).define(async (ctx) => {
const cnb = await cnbManager.getContext(ctx);
let repo = ctx.query?.repo || useKey('CNB_REPO_SLUG_LOWERCASE');
const issueNumber = ctx.query?.issueNumber;
const commentId = ctx.query?.commentId;
if (!repo) {
ctx.throw(400, '缺少参数 repo');
}
if (!issueNumber) {
ctx.throw(400, '缺少参数 issueNumber');
}
if (!commentId) {
ctx.throw(400, '缺少参数 commentId');
}
const res = await cnb.issue.getComment(repo, issueNumber, commentId);
ctx.forward(res);
}).addTo(app);
// 修改 Issue 评论
app.route({
path: 'cnb',
key: 'update-issue-comment',
description: '修改 Issue 评论, 参数 repo, issueNumber, commentId, body',
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
skill: 'update-issue-comment',
title: '修改 Issue 评论',
args: {
repo: tool.schema.string().optional().describe('代码仓库名称, 如 my-user/my-repo'),
issueNumber: tool.schema.number().describe('Issue 编号'),
commentId: tool.schema.number().describe('评论 ID'),
body: tool.schema.string().describe('评论内容'),
clearAt: tool.schema.boolean().optional().describe('是否清除评论内容中的 @ 提及,默认: true'),
},
summary: '修改 Issue 评论',
})
}
}).define(async (ctx) => {
const cnb = await cnbManager.getContext(ctx);
let repo = ctx.query?.repo || useKey('CNB_REPO_SLUG_LOWERCASE');
const issueNumber = ctx.query?.issueNumber;
const commentId = ctx.query?.commentId;
let body = ctx.query?.body;
const clearAt = ctx.query?.clearAt ?? true;
if (!repo) {
ctx.throw(400, '缺少参数 repo');
}
if (!issueNumber) {
ctx.throw(400, '缺少参数 issueNumber');
}
if (!commentId) {
ctx.throw(400, '缺少参数 commentId');
}
if (!body) {
ctx.throw(400, '缺少参数 body');
}
if (clearAt && body) {
// 清除评论内容中的 @ 提及
body = body.replace(/@/g, '');
}
const res = await cnb.issue.updateComment(repo, issueNumber, commentId, body);
ctx.forward(res);
}).addTo(app);

View File

@@ -1,2 +1,3 @@
import './list.ts'
import './issue.ts'
import './issue.ts'
import './comments.ts'

View File

@@ -1,5 +1,5 @@
import { createSkill, tool } from '@kevisual/router';
import { app, cnb } from '../../app.ts';
import { app, cnbManager } from '../../app.ts';
import { IssueItem } from '@/index.ts';
// 创建cnb issue, 仓库为 kevisual/kevisual 标题为 "自动化测试创建issue", 内容为 "这是通过API创建的issue用于测试目的", body: "这是通过API创建的issue用于测试目的"
@@ -7,7 +7,7 @@ app.route({
path: 'cnb',
key: 'create-issue',
description: '创建 Issue, 参数 repo, title, body, assignees, labels, priority',
middleware: ['auth-admin'],
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
@@ -25,6 +25,7 @@ app.route({
})
}
}).define(async (ctx) => {
const cnb = await cnbManager.getContext(ctx);
const repo = ctx.query?.repo;
const title = ctx.query?.title;
const body = ctx.query?.body;
@@ -51,7 +52,7 @@ app.route({
path: 'cnb',
key: 'complete-issue',
description: '完成 Issue, 参数 repo, issueNumber',
middleware: ['auth-admin'],
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
@@ -66,6 +67,7 @@ app.route({
})
}
}).define(async (ctx) => {
const cnb = await cnbManager.getContext(ctx);
const repo = ctx.query?.repo;
const issueNumber = ctx.query?.issueNumber;
const state = ctx.query?.state ?? 'closed';

View File

@@ -1,5 +1,5 @@
import { createSkill, tool } from '@kevisual/router';
import { app, cnb } from '../../app.ts';
import { app, cnbManager } from '../../app.ts';
import { useKey } from '@kevisual/context';
// 查询 Issue 列表 repo是 kevisual/kevisual
@@ -7,14 +7,14 @@ app.route({
path: 'cnb',
key: 'list-issues',
description: '查询 Issue 列表, 参数 repo, state, keyword, labels, page, page_size 等',
middleware: ['auth-admin'],
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
skill: 'list-issues',
title: '查询 Issue 列表',
args: {
repo: tool.schema.string().describe('代码仓库名称, 如 my-user/my-repo'),
repo: tool.schema.string().optional().describe('代码仓库名称, 如 my-user/my-repo'),
state: tool.schema.string().optional().describe('Issue 状态open 或 closed'),
keyword: tool.schema.string().optional().describe('问题搜索关键词'),
labels: tool.schema.string().optional().describe('问题标签,多个用逗号分隔'),
@@ -26,7 +26,8 @@ app.route({
})
}
}).define(async (ctx) => {
const repo = ctx.query?.repo || useKey('CNB_REPO_SLUG_LOWERCASE');
const cnb = await cnbManager.getContext(ctx);
let repo = ctx.query?.repo || useKey('CNB_REPO_SLUG_LOWERCASE');
const state = ctx.query?.state;
const keyword = ctx.query?.keyword;
const labels = ctx.query?.labels;
@@ -48,4 +49,37 @@ app.route({
const res = await cnb.issue.getList(repo, params);
ctx.forward(res);
}).addTo(app);
app.route({
path: 'cnb',
key: 'getIssue',
description: '获取 单个 Issue',
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
skill: 'getIssue',
title: '获取 单个 Issue',
args: {
repo: tool.schema.string().optional().describe('代码仓库名称, 如 my-user/my-repo'),
issueNumber: tool.schema.union([tool.schema.string(), tool.schema.number()]).describe('Issue 编号'),
},
summary: '获取 单个 Issue',
})
}
}).define(async (ctx) => {
const cnb = await cnbManager.getContext(ctx);
let repo = ctx.query?.repo || useKey('CNB_REPO_SLUG_LOWERCASE');
const issueNumber = ctx.query?.issueNumber;
if (!repo) {
ctx.throw(400, '缺少参数 repo');
}
if (!issueNumber) {
ctx.throw(400, '缺少参数 issueNumber');
}
const res = await cnb.issue.getItem(repo, issueNumber);
ctx.forward(res);
}).addTo(app);

View File

@@ -1,5 +1,5 @@
import { createSkill, tool } from '@kevisual/router';
import { app, cnb } from '../../app.ts';
import { app, cnbManager } from '../../app.ts';
import { CNBChat } from '@kevisual/ai/browser'
import { useKey } from '@kevisual/context';
@@ -13,7 +13,7 @@ app.route({
path: 'cnb',
key: 'cnb-ai-chat',
description: '调用cnb的知识库ai对话功能进行聊天',
middleware: ['auth-admin'],
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
@@ -27,6 +27,7 @@ app.route({
})
}
}).define(async (ctx) => {
const cnb = await cnbManager.getContext(ctx);
const question = ctx.query?.question;
if (!question) {
ctx.body = { content: '请提供有效的消息内容' };
@@ -89,7 +90,7 @@ app.route({
path: 'cnb',
key: 'cnb-rag-query',
description: '调用cnb的知识库RAG查询功能进行问答',
middleware: ['auth-admin'],
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
@@ -103,6 +104,7 @@ app.route({
})
}
}).define(async (ctx) => {
const cnb = await cnbManager.getContext(ctx);
const question = ctx.query?.question;
if (!question) {
ctx.body = { content: '请提供有效的消息内容' };

View File

@@ -0,0 +1,12 @@
import { createOpencodeClient } from "@opencode-ai/sdk"
const client = await createOpencodeClient({
// baseUrl: "https://yccb64t1z-100.cnb.run",
// auth: async () => {
// return 'cm9vdDozR0I2MDg5ZGpYOE5oMDFjM1FteE5DWDd0ZkI='
// }
baseUrl: "http://localhost:4096",
})
const sessionList = await client.session.list()
console.log(sessionList.data)

View File

@@ -1,5 +1,5 @@
import { createSkill, tool } from '@kevisual/router';
import { app, cnb } from '../../app.ts';
import { app, cnbManager } from '../../app.ts';
// "列出我的代码仓库search blog"
// 列出我的知识库的代码仓库
@@ -7,7 +7,7 @@ app.route({
path: 'cnb',
key: 'list-repos',
description: '列出我的代码仓库',
middleware: ['auth-admin'],
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
@@ -22,6 +22,7 @@ app.route({
})
}
}).define(async (ctx) => {
const cnb = await cnbManager.getContext(ctx);
const search = ctx.query?.search;
const pageSize = ctx.query?.pageSize || 9999;
const flags = ctx.query?.flags;

View File

@@ -1,4 +1,4 @@
import { app, cnb } from '../../app.ts';
import { app, cnbManager } from '../../app.ts';
import { createSkill, Skill, tool } from '@kevisual/router'
// 创建一个仓库 kevisual/test-repo
@@ -6,7 +6,7 @@ app.route({
path: 'cnb',
key: 'create-repo',
description: '创建代码仓库, 参数name, visibility, description',
middleware: ['auth-admin'],
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
@@ -21,6 +21,7 @@ app.route({
})
}
}).define(async (ctx) => {
const cnb = await cnbManager.getContext(ctx);
const name = ctx.query?.name;
const visibility = ctx.query?.visibility ?? 'public';
const description = ctx.query?.description ?? '';
@@ -42,11 +43,32 @@ app.route({
}
}).addTo(app);
app.route({
path: 'cnb',
key: 'get-repo',
description: '获取代码仓库详情, 参数name',
middleware: ['auth'],
metadata: {
args: {
name: tool.schema.string().describe('代码仓库名称, 如 my-user/my-repo'),
}
}
}).define(async (ctx) => {
const cnb = await cnbManager.getContext(ctx);
const name = ctx.query?.name;
if (!name) {
ctx.throw(400, '缺少参数 name');
}
const res = await cnb.repo.getRepo(name);
ctx.forward(res);
}).addTo(app);
app.route({
path: 'cnb',
key: 'create-repo-file',
description: '在代码仓库中创建文件, repoName, filePath, content, encoding。使用CNB_COOKIE进行鉴权',
middleware: ['auth-admin'],
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
@@ -62,6 +84,7 @@ app.route({
})
}
}).define(async (ctx) => {
const cnb = await cnbManager.getContext(ctx);
const repoName = ctx.query?.repoName;
const filePath = ctx.query?.filePath;
const content = ctx.query?.content;
@@ -85,7 +108,7 @@ app.route({
path: 'cnb',
key: 'delete-repo',
description: '删除代码仓库, 参数name',
middleware: ['auth-admin'],
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
@@ -98,12 +121,62 @@ app.route({
})
}
}).define(async (ctx) => {
const cnb = await cnbManager.getContext(ctx);
const name = ctx.query?.name;
if (!name) {
ctx.throw(400, '缺少参数 name');
}
try {
const resCookie = await cnb.user.checkCookieValid()
if (resCookie.code !== 200) {
ctx.throw(401, 'Cookie 无效或已过期');
}
const res = await cnb.repo.deleteRepoCookie(name);
ctx.forward(res);
} catch (error) {
ctx.code = 200
ctx.body = { content: '已经删除' }
}
}).addTo(app);
const res = await cnb.repo.deleteRepo(name);
app.route({
path: 'cnb',
key: 'update-repo-info',
description: '更新代码仓库信息, 参数name, description',
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
skill: 'update-repo-info',
title: '更新代码仓库信息',
args: {
name: tool.schema.string().describe('代码仓库名称'),
description: tool.schema.string().describe('代码仓库描述'),
license: tool.schema.string().describe('代码仓库许可证类型,如 MIT').optional(),
site: tool.schema.string().describe('代码仓库主页链接').optional(),
topics: tool.schema.array(tool.schema.string()).describe('代码仓库话题标签列表').optional(),
},
summary: '更新代码仓库的信息',
})
}
}).define(async (ctx) => {
const cnb = await cnbManager.getContext(ctx);
const name = ctx.query?.name;
const description = ctx.query?.description;
const license = ctx.query?.license;
const site = ctx.query?.site;
const topics = ctx.query?.topics;
if (!name) {
ctx.throw(400, '缺少参数 name');
}
if (!description) {
ctx.throw(400, '缺少参数 description');
}
const res = await cnb.repo.updateRepoInfo(name, { description, license, site, topics });
ctx.forward(res);
}).addTo(app);
}).addTo(app);

View File

@@ -1,5 +1,5 @@
import { useKey } from '@kevisual/context';
import { app, cnb } from '../../app.ts';
import { app } from '../../app.ts';
import z from 'zod';
app.route({

View File

@@ -0,0 +1,43 @@
import { createSkill, tool } from '@kevisual/router';
import { app, cnbManager, notCNBCheck } from '../../app.ts';
// 启动工作空间
app.route({
path: 'cnb',
key: 'cloud-build',
description: '云端构建,参数 event, repo, branch, ref, config, env',
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
skill: 'cloud-build',
title: '云端构建',
summary: '在云端构建代码仓库,参数包括 event, repo, branch, ref, config, env',
args: {
env: tool.schema.any().optional().describe('构建环境变量,格式为 { "KEY": "VALUE" }'),
event: tool.schema.string().optional().describe('触发事件类型,例如 api_trigger_event'),
branch: tool.schema.string().optional().describe('分支名称,默认主分支'),
config: tool.schema.string().describe('构建config文件内容例如 cloudbuild.yaml对应的yml的内容'),
repo: tool.schema.string().describe('代码仓库路径,例如 user/repo'),
},
})
}
}).define(async (ctx) => {
const cnb = await cnbManager.getContext(ctx);
const repo = ctx.query?.repo;
const branch = ctx.query?.branch || 'main';
const config = ctx.query?.config;
const event = ctx.query?.event || 'api_trigger_event';
const env = ctx.query?.env ?? {};
if (!repo) {
ctx.throw(400, '缺少参数 repo');
}
const res = await cnb.build.startBuild(repo, {
branch,
config,
event,
env,
});
ctx.forward(res);
}).addTo(app);

View File

@@ -1,15 +1,16 @@
import { createSkill, tool } from '@kevisual/router';
import { app, cnb } from '../../app.ts';
import { app, cnbManager, notCNBCheck } from '../../app.ts';
import z from 'zod';
import './skills.ts';
import './keep.ts';
import './build.ts';
// 启动工作空间
app.route({
path: 'cnb',
key: 'start-workspace',
description: '启动开发工作空间, 参数 repo',
middleware: ['auth-admin'],
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
@@ -24,6 +25,7 @@ app.route({
})
}
}).define(async (ctx) => {
const cnb = await cnbManager.getContext(ctx);
const repo = ctx.query?.repo;
const branch = ctx.query?.branch;
const ref = ctx.query?.ref;
@@ -42,7 +44,7 @@ app.route({
path: 'cnb',
key: 'list-workspace',
description: '获取cnb开发工作空间列表可选参数 status=running 获取运行中的环境',
middleware: ['auth-admin'],
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
@@ -59,13 +61,14 @@ app.route({
})
}
}).define(async (ctx) => {
const cnb = await cnbManager.getContext(ctx);
const { status = 'running', page, pageSize, slug, branch } = ctx.query || {};
const res = await cnb.workspace.list({
status: status as 'running' | 'closed' | undefined,
page: page ?? 1,
pageSize: pageSize ?? 100,
});
ctx.forward({ code: 200, message: 'success', data: res });
ctx.forward(res);
}).addTo(app);
// 获取工作空间详情
@@ -73,7 +76,7 @@ app.route({
path: 'cnb',
key: 'get-workspace',
description: '获取工作空间详情,通过 repo 和 sn 获取',
middleware: ['auth-admin'],
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
@@ -87,6 +90,7 @@ app.route({
})
}
}).define(async (ctx) => {
const cnb = await cnbManager.getContext(ctx);
const repo = ctx.query?.repo;
const sn = ctx.query?.sn;
if (!repo) {
@@ -96,7 +100,7 @@ app.route({
ctx.throw(400, '缺少参数 sn');
}
const res = await cnb.workspace.getDetail(repo, sn);
ctx.forward({ code: 200, message: 'success', data: res });
ctx.forward(res);
}).addTo(app);
// 删除工作空间
@@ -104,7 +108,7 @@ app.route({
path: 'cnb',
key: 'delete-workspace',
description: '删除工作空间,通过 pipelineId 或 sn',
middleware: ['auth-admin'],
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
@@ -119,6 +123,7 @@ app.route({
})
}
}).define(async (ctx) => {
const cnb = await cnbManager.getContext(ctx);
const pipelineId = ctx.query?.pipelineId;
const sn = ctx.query?.sn;
const sns = ctx.query?.sns;
@@ -143,7 +148,7 @@ app.route({
path: 'cnb',
key: 'stop-workspace',
description: '停止工作空间,通过 pipelineId 或 sn',
middleware: ['auth-admin'],
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
@@ -157,12 +162,14 @@ app.route({
})
}
}).define(async (ctx) => {
const cnb = await cnbManager.getContext(ctx);
const pipelineId = ctx.query?.pipelineId;
const sn = ctx.query?.sn;
if (!pipelineId && !sn) {
ctx.throw(400, 'pipelineId 和 sn 必须提供其中一个');
}
const res = await cnb.workspace.stopWorkspace({ pipelineId, sn });
ctx.forward({ code: 200, message: 'success', data: res });
ctx.forward(res);
}).addTo(app);

View File

@@ -1,5 +1,5 @@
import { tool } from '@kevisual/router';
import { app, cnb } from '../../app.ts';
import { app, cnbManager, notCNBCheck } from '../../app.ts';
import { addKeepAliveData, KeepAliveData, removeKeepAliveData, createLiveData } from '../../../src/workspace/keep-file-live.ts';
import { useKey } from '@kevisual/context';
@@ -8,7 +8,7 @@ app.route({
path: 'cnb',
key: 'keep-workspace-alive',
description: '保持工作空间存活技能参数repo:代码仓库路径,例如 user/repopipelineId:流水线ID例如 cnb-708-1ji9sog7o-001',
middleware: ['auth-admin'],
middleware: ['auth'],
metadata: {
tags: [],
...({
@@ -19,9 +19,11 @@ app.route({
})
}
}).define(async (ctx) => {
const cnb = await cnbManager.getContext(ctx);
const repo = ctx.query?.repo as string;
const pipelineId = ctx.query?.pipelineId as string;
if (notCNBCheck(ctx)) return;
if (!repo || !pipelineId) {
ctx.throw(400, '缺少参数 repo 或 pipelineId');
}
@@ -51,7 +53,7 @@ app.route({
path: 'cnb',
key: 'stop-keep-workspace-alive',
description: '停止保持工作空间存活技能, 参数repo:代码仓库路径,例如 user/repopipelineId:流水线ID例如 cnb-708-1ji9sog7o-001',
middleware: ['auth-admin'],
middleware: ['auth'],
metadata: {
tags: [],
...({
@@ -62,6 +64,7 @@ app.route({
})
}
}).define(async (ctx) => {
if (notCNBCheck(ctx)) return;
const repo = ctx.query?.repo as string;
const pipelineId = ctx.query?.pipelineId as string;
@@ -79,7 +82,7 @@ app.route({
path: 'cnb',
key: 'keep-alive-current-workspace',
description: '保持当前工作空间存活技能',
middleware: ['auth-admin'],
middleware: ['auth'],
metadata: {
tags: ['opencode'],
skill: 'keep-alive-current-workspace',
@@ -87,6 +90,7 @@ app.route({
summary: '保持当前工作空间存活,防止被关闭或释放资源',
}
}).define(async (ctx) => {
if (notCNBCheck(ctx)) return;
const pipelineId = useKey('CNB_PIPELINE_ID');
const repo = useKey('CNB_REPO_SLUG_LOWERCASE');
if (!pipelineId || !repo) {

View File

@@ -1,5 +1,5 @@
import { createSkill, tool } from '@kevisual/router';
import { app, cnb } from '../../app.ts';
import { app, cnbManager } from '../../app.ts';
// 批量删除已停止的cnb工作空间
// app.route({
@@ -35,7 +35,7 @@ app.route({
path: 'cnb',
key: 'clean-closed-workspace',
description: '批量删除已停止的cnb工作空间',
middleware: ['auth-admin'],
middleware: ['auth'],
metadata: {
tags: ['opencode'],
...createSkill({
@@ -45,6 +45,7 @@ app.route({
})
}
}).define(async (ctx) => {
const cnb = await cnbManager.getContext(ctx);
const closedWorkspaces = await cnb.workspace.list({ status: 'closed', pageSize: 100 });
if (closedWorkspaces.code !== 200) {
ctx.throw(500, '获取已关闭工作空间列表失败');

2
bin/npc.js Executable file
View File

@@ -0,0 +1,2 @@
#!/usr/bin/env bun
import '../dist/npc.js';

View File

@@ -3,4 +3,5 @@ await buildWithBun({ naming: 'opencode', entry: 'agent/opencode.ts', dts: true }
await buildWithBun({ naming: 'keep', entry: 'src/keep.ts', dts: true, target: 'node' });
await buildWithBun({ naming: 'routes', entry: 'agent/index.ts', dts: true });
await buildWithBun({ naming: 'cli', entry: 'agent/command.ts', dts: true, target: 'node' });
await buildWithBun({ naming: 'npc', entry: 'agent/npc.ts', dts: true });
await buildWithBun({ naming: 'cli', entry: 'agent/cli.ts', dts: true, target: 'node' });

284
bun.lock
View File

@@ -5,26 +5,32 @@
"": {
"name": "@kevisual/cnb",
"dependencies": {
"@kevisual/query": "^0.0.49",
"@kevisual/router": "^0.0.80",
"@kevisual/query": "^0.0.53",
"@kevisual/router": "^0.1.2",
"@kevisual/use-config": "^1.0.30",
"es-toolkit": "^1.44.0",
"nanoid": "^5.1.6",
"@opencode-ai/sdk": "^1.2.27",
"es-toolkit": "^1.45.1",
"nanoid": "^5.1.7",
"unstorage": "^1.17.4",
"ws": "npm:@kevisual/ws",
"zod": "^4.3.6",
},
"devDependencies": {
"@kevisual/ai": "^0.0.24",
"@ai-sdk/openai-compatible": "^2.0.35",
"@kevisual/ai": "^0.0.28",
"@kevisual/api": "^0.0.64",
"@kevisual/code-builder": "^0.0.6",
"@kevisual/context": "^0.0.8",
"@kevisual/dts": "^0.0.4",
"@kevisual/remote-app": "^0.0.7",
"@kevisual/types": "^0.0.12",
"@opencode-ai/plugin": "^1.2.10",
"@types/bun": "^1.3.9",
"@types/node": "^25.3.0",
"@opencode-ai/plugin": "^1.2.27",
"@types/bun": "^1.3.10",
"@types/node": "^25.5.0",
"@types/ws": "^8.18.1",
"dayjs": "^1.11.19",
"ai": "^6.0.116",
"commander": "^14.0.3",
"dayjs": "^1.11.20",
"dotenv": "^17.3.1",
},
},
@@ -33,204 +39,264 @@
"zod": "^4.3.6",
},
"packages": {
"@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="],
"@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.58", "https://registry.npmmirror.com/@ai-sdk/anthropic/-/anthropic-3.0.58.tgz", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.19" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-/53SACgmVukO4bkms4dpxpRlYhW8Ct6QZRe6sj1Pi5H00hYhxIrqfiLbZBGxkdRvjsBQeP/4TVGsXgH5rQeb8Q=="],
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
"@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.66", "https://registry.npmmirror.com/@ai-sdk/gateway/-/gateway-3.0.66.tgz", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.19", "@vercel/oidc": "3.1.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-SIQ0YY0iMuv+07HLsZ+bB990zUJ6S4ujORAh+Jv1V2KGNn73qQKnGO0JBk+w+Res8YqOFSycwDoWcFlQrVxS4A=="],
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
"@ai-sdk/openai": ["@ai-sdk/openai@3.0.41", "https://registry.npmmirror.com/@ai-sdk/openai/-/openai-3.0.41.tgz", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.19" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-IZ42A+FO+vuEQCVNqlnAPYQnnUpUfdJIwn1BEDOBywiEHa23fw7PahxVtlX9zm3/zMvTW4JKPzWyvAgDu+SQ2A=="],
"@kevisual/ai": ["@kevisual/ai@0.0.24", "", { "dependencies": { "@kevisual/logger": "^0.0.4", "@kevisual/permission": "^0.0.3", "@kevisual/query": "^0.0.38" } }, "sha512-7jvZk1/L//VIClK7usuNgN4ZA9Etgbooka1Sj5quE/0UywR+NNnwqXVZ89Y1fBhI1TkhauDsdJBAtcQ7r/vbVw=="],
"@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.35", "https://registry.npmmirror.com/@ai-sdk/openai-compatible/-/openai-compatible-2.0.35.tgz", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.19" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-g3wA57IAQFb+3j4YuFndgkUdXyRETZVvbfAWM+UX7bZSxA3xjes0v3XKgIdKdekPtDGsh4ZX2byHD0gJIMPfiA=="],
"@kevisual/code-builder": ["@kevisual/code-builder@0.0.6", "", { "bin": { "code-builder": "bin/code.js", "builder": "bin/code.js" } }, "sha512-0aqATB31/yw4k4s5/xKnfr4DKbUnx8e3Z3BmKbiXTrc+CqWiWTdlGe9bKI9dZ2Df+xNp6g11W4xM2NICNyyCCw=="],
"@ai-sdk/provider": ["@ai-sdk/provider@3.0.8", "https://registry.npmmirror.com/@ai-sdk/provider/-/provider-3.0.8.tgz", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ=="],
"@kevisual/context": ["@kevisual/context@0.0.8", "", {}, "sha512-DTJpyHI34NE76B7g6f+QlIqiCCyqI2qkBMQE736dzeRDGxOjnbe2iQY9W+Rt2PE6kmymM3qyOmSfNovyWyWrkA=="],
"@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.19", "https://registry.npmmirror.com/@ai-sdk/provider-utils/-/provider-utils-4.0.19.tgz", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-3eG55CrSWCu2SXlqq2QCsFjo3+E7+Gmg7i/oRVoSZzIodTuDSfLb3MRje67xE9RFea73Zao7Lm4mADIfUETKGg=="],
"@kevisual/dts": ["@kevisual/dts@0.0.4", "", { "dependencies": { "@rollup/plugin-commonjs": "^29.0.0", "@rollup/plugin-node-resolve": "^16.0.3", "@rollup/plugin-typescript": "^12.3.0", "rollup": "^4.57.1", "rollup-plugin-dts": "^6.3.0", "tslib": "^2.8.1" }, "bin": { "dts": "bin/dts.mjs" } }, "sha512-FVUaH/0nyhbHWpEVjFTGP54PLMm4Hf06aqWLdHOYHNPIgr1aK1C26kOH7iumklGFGk9w93IGxj8Zxe5fap5N2A=="],
"@babel/code-frame": ["@babel/code-frame@7.29.0", "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.29.0.tgz", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="],
"@kevisual/load": ["@kevisual/load@0.0.6", "", { "dependencies": { "eventemitter3": "^5.0.1" } }, "sha512-+3YTFehRcZ1haGel5DKYMUwmi5i6f2psyaPZlfkKU/cOXgkpwoG9/BEqPCnPjicKqqnksEpixVRkyHJ+5bjLVA=="],
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
"@kevisual/logger": ["@kevisual/logger@0.0.4", "", {}, "sha512-+fpr92eokSxoGOW1SIRl/27lPuO+zyY+feR5o2Q4YCNlAdt2x64NwC/w8r/3NEC5QenLgd4K0azyKTI2mHbARw=="],
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
"@kevisual/permission": ["@kevisual/permission@0.0.3", "", {}, "sha512-8JsA/5O5Ax/z+M+MYpFYdlioHE6jNmWMuFSokBWYs9CCAHNiSKMR01YLkoVDoPvncfH/Y8F5K/IEXRCbptuMNA=="],
"@kevisual/ai": ["@kevisual/ai@0.0.28", "https://registry.npmmirror.com/@kevisual/ai/-/ai-0.0.28.tgz", { "dependencies": { "@ai-sdk/anthropic": "^3.0.58", "@ai-sdk/openai": "^3.0.41", "@ai-sdk/openai-compatible": "^2.0.35", "@kevisual/js-filter": "^0.0.6", "@kevisual/logger": "^0.0.4", "@kevisual/permission": "^0.0.4", "@kevisual/query": "^0.0.53", "ai": "^6.0.116", "zod": "^4.3.6" } }, "sha512-GLwCNXfopDvOj+hEZwEIwOV2/3VGd+TCPgBClaYuAv30KzhgehlCW05HPjBducSg+uPcdKacEzZsecHjo5fMUQ=="],
"@kevisual/query": ["@kevisual/query@0.0.49", "", {}, "sha512-GrWW+QlBO5lkiqvb7PjOstNtpTQVSR74EHHWjm7YoL9UdT1wuPQXGUApZHmMBSh3NIWCf0AL2G1hPWZMC7YeOQ=="],
"@kevisual/api": ["@kevisual/api@0.0.64", "http://mirrors.tencent.com/npm/@kevisual/api/-/api-0.0.64.tgz", { "dependencies": { "@kevisual/context": "^0.0.8", "@kevisual/js-filter": "^0.0.6", "@kevisual/load": "^0.0.6", "@paralleldrive/cuid2": "^3.3.0", "es-toolkit": "^1.45.1", "eventemitter3": "^5.0.4", "fuse.js": "^7.1.0", "nanoid": "^5.1.6", "path-browserify-esm": "^1.0.6", "sonner": "^2.0.7", "spark-md5": "^3.0.2", "zustand": "^5.0.11" } }, "sha512-y7wP8ucvi/rflVGd6uJpvuEUTwI7wMef8+ITQzv4flg7a2pwWZYe/DT0TOyaqDAqKOTlXaVIdBeI15jXuUxIIg=="],
"@kevisual/router": ["@kevisual/router@0.0.80", "", { "dependencies": { "es-toolkit": "^1.44.0" } }, "sha512-rVwi6Yf411bnNm2x94lMm+s4Csw0Yb7u/aj+VJJ59iouAYhjLuL7Rs1EcARhnQf47cegBJi6zozfGHgLsLHN2w=="],
"@kevisual/code-builder": ["@kevisual/code-builder@0.0.6", "https://registry.npmmirror.com/@kevisual/code-builder/-/code-builder-0.0.6.tgz", { "bin": { "code-builder": "bin/code.js", "builder": "bin/code.js" } }, "sha512-0aqATB31/yw4k4s5/xKnfr4DKbUnx8e3Z3BmKbiXTrc+CqWiWTdlGe9bKI9dZ2Df+xNp6g11W4xM2NICNyyCCw=="],
"@kevisual/types": ["@kevisual/types@0.0.12", "", {}, "sha512-zJXH2dosir3jVrQ6QG4i0+iLQeT9gJ3H+cKXs8ReWboxBSYzUZO78XssVeVrFPsJ33iaAqo4q3DWbSS1dWGn7Q=="],
"@kevisual/context": ["@kevisual/context@0.0.8", "https://registry.npmmirror.com/@kevisual/context/-/context-0.0.8.tgz", {}, "sha512-DTJpyHI34NE76B7g6f+QlIqiCCyqI2qkBMQE736dzeRDGxOjnbe2iQY9W+Rt2PE6kmymM3qyOmSfNovyWyWrkA=="],
"@kevisual/use-config": ["@kevisual/use-config@1.0.30", "", { "dependencies": { "@kevisual/load": "^0.0.6" }, "peerDependencies": { "dotenv": "^17" } }, "sha512-kPdna0FW/X7D600aMdiZ5UTjbCo6d8d4jjauSc8RMmBwUU6WliFDSPUNKVpzm2BsDX5Nth1IXFPYMqH+wxqAmw=="],
"@kevisual/dts": ["@kevisual/dts@0.0.4", "https://registry.npmmirror.com/@kevisual/dts/-/dts-0.0.4.tgz", { "dependencies": { "@rollup/plugin-commonjs": "^29.0.0", "@rollup/plugin-node-resolve": "^16.0.3", "@rollup/plugin-typescript": "^12.3.0", "rollup": "^4.57.1", "rollup-plugin-dts": "^6.3.0", "tslib": "^2.8.1" }, "bin": { "dts": "bin/dts.mjs" } }, "sha512-FVUaH/0nyhbHWpEVjFTGP54PLMm4Hf06aqWLdHOYHNPIgr1aK1C26kOH7iumklGFGk9w93IGxj8Zxe5fap5N2A=="],
"@opencode-ai/plugin": ["@opencode-ai/plugin@1.2.10", "", { "dependencies": { "@opencode-ai/sdk": "1.2.10", "zod": "4.1.8" } }, "sha512-Z1BMqNHnD8AGAEb+kUz0b2SOuiODwdQLdCA4aVGTXqkGzhiD44OVxr85MeoJ5AMTnnea9SnJ3jp9GAQ5riXA5g=="],
"@kevisual/js-filter": ["@kevisual/js-filter@0.0.6", "https://registry.npmmirror.com/@kevisual/js-filter/-/js-filter-0.0.6.tgz", {}, "sha512-FcbOsmS1inhwrfgXMM/XLFTGTHUxBCss32JEMYdEFWQDYCar5rN8cxD1W8FuKDTVRlpA+zBpQ/BE6XT4UaeljA=="],
"@opencode-ai/sdk": ["@opencode-ai/sdk@1.2.10", "", {}, "sha512-SyXcVqry2hitPVvQtvXOhqsWyFhSycG/+LTLYXrcq8AFmd9FR7dyBSDB3f5Ol6IPkYOegk8P2Eg2kKPNSNiKGw=="],
"@kevisual/load": ["@kevisual/load@0.0.6", "https://registry.npmmirror.com/@kevisual/load/-/load-0.0.6.tgz", { "dependencies": { "eventemitter3": "^5.0.1" } }, "sha512-+3YTFehRcZ1haGel5DKYMUwmi5i6f2psyaPZlfkKU/cOXgkpwoG9/BEqPCnPjicKqqnksEpixVRkyHJ+5bjLVA=="],
"@rollup/plugin-commonjs": ["@rollup/plugin-commonjs@29.0.0", "", { "dependencies": { "@rollup/pluginutils": "^5.0.1", "commondir": "^1.0.1", "estree-walker": "^2.0.2", "fdir": "^6.2.0", "is-reference": "1.2.1", "magic-string": "^0.30.3", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^2.68.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-U2YHaxR2cU/yAiwKJtJRhnyLk7cifnQw0zUpISsocBDoHDJn+HTV74ABqnwr5bEgWUwFZC9oFL6wLe21lHu5eQ=="],
"@kevisual/logger": ["@kevisual/logger@0.0.4", "https://registry.npmmirror.com/@kevisual/logger/-/logger-0.0.4.tgz", {}, "sha512-+fpr92eokSxoGOW1SIRl/27lPuO+zyY+feR5o2Q4YCNlAdt2x64NwC/w8r/3NEC5QenLgd4K0azyKTI2mHbARw=="],
"@rollup/plugin-node-resolve": ["@rollup/plugin-node-resolve@16.0.3", "", { "dependencies": { "@rollup/pluginutils": "^5.0.1", "@types/resolve": "1.20.2", "deepmerge": "^4.2.2", "is-module": "^1.0.0", "resolve": "^1.22.1" }, "peerDependencies": { "rollup": "^2.78.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg=="],
"@kevisual/permission": ["@kevisual/permission@0.0.4", "https://registry.npmmirror.com/@kevisual/permission/-/permission-0.0.4.tgz", {}, "sha512-zwBYPnT/z21W4q2wkklJrxvoYBYWG/+a3iXFDKqXQAnDOcxm/SU1f1N6FQb9KxGKl36/fclVlhxlxqszvKCenQ=="],
"@rollup/plugin-typescript": ["@rollup/plugin-typescript@12.3.0", "", { "dependencies": { "@rollup/pluginutils": "^5.1.0", "resolve": "^1.22.1" }, "peerDependencies": { "rollup": "^2.14.0||^3.0.0||^4.0.0", "tslib": "*", "typescript": ">=3.7.0" }, "optionalPeers": ["rollup", "tslib"] }, "sha512-7DP0/p7y3t67+NabT9f8oTBFE6gGkto4SA6Np2oudYmZE/m1dt8RB0SjL1msMxFpLo631qjRCcBlAbq1ml/Big=="],
"@kevisual/query": ["@kevisual/query@0.0.53", "https://registry.npmmirror.com/@kevisual/query/-/query-0.0.53.tgz", {}, "sha512-PAhpCLBr0emz0lGNlTVHMbJiC5wrtGLbInPddRzgKE35fiyNt+SWSsUWABiD0DeNrLN/OxWyAFobt880Z/e5MQ=="],
"@rollup/pluginutils": ["@rollup/pluginutils@5.3.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q=="],
"@kevisual/remote-app": ["@kevisual/remote-app@0.0.7", "http://mirrors.tencent.com/npm/@kevisual/remote-app/-/remote-app-0.0.7.tgz", {}, "sha512-d0P8uyxoMnmyT8x1J9XC9ecDBbqW+jOP0ZM5fCgQRDUhWw35V/MnbCD4hNG4b6EmvoiS6a/PBC7RC5JGm3wpCg=="],
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.57.1", "", { "os": "android", "cpu": "arm" }, "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg=="],
"@kevisual/router": ["@kevisual/router@0.1.2", "http://mirrors.tencent.com/npm/@kevisual/router/-/router-0.1.2.tgz", { "dependencies": { "crypto-js": "^4.2.0", "es-toolkit": "^1.45.1", "zod": "^4.3.6" } }, "sha512-GLLJMZXtv3nUQKJXyE+vJFiCuntpuBc0VT8hMQyGvxwzqN8BY8rX6yS9TNDWhSXLwLYed8BJtG+azEONDjFCpw=="],
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.57.1", "", { "os": "android", "cpu": "arm64" }, "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w=="],
"@kevisual/types": ["@kevisual/types@0.0.12", "https://registry.npmmirror.com/@kevisual/types/-/types-0.0.12.tgz", {}, "sha512-zJXH2dosir3jVrQ6QG4i0+iLQeT9gJ3H+cKXs8ReWboxBSYzUZO78XssVeVrFPsJ33iaAqo4q3DWbSS1dWGn7Q=="],
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.57.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg=="],
"@kevisual/use-config": ["@kevisual/use-config@1.0.30", "https://registry.npmmirror.com/@kevisual/use-config/-/use-config-1.0.30.tgz", { "dependencies": { "@kevisual/load": "^0.0.6" }, "peerDependencies": { "dotenv": "^17" } }, "sha512-kPdna0FW/X7D600aMdiZ5UTjbCo6d8d4jjauSc8RMmBwUU6WliFDSPUNKVpzm2BsDX5Nth1IXFPYMqH+wxqAmw=="],
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.57.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w=="],
"@noble/hashes": ["@noble/hashes@2.0.1", "https://registry.npmmirror.com/@noble/hashes/-/hashes-2.0.1.tgz", {}, "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw=="],
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.57.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug=="],
"@opencode-ai/plugin": ["@opencode-ai/plugin@1.2.27", "http://mirrors.tencent.com/npm/@opencode-ai/plugin/-/plugin-1.2.27.tgz", { "dependencies": { "@opencode-ai/sdk": "1.2.27", "zod": "4.1.8" } }, "sha512-h+8Bw9v9nghMg7T+SUCTzxlIhOrsTqXW7U0HVLGQST5DjbN7uyCUM51roZWZ8LRjGxzbzFhvPnY1bj8i+ioZyw=="],
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.57.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q=="],
"@opencode-ai/sdk": ["@opencode-ai/sdk@1.2.27", "http://mirrors.tencent.com/npm/@opencode-ai/sdk/-/sdk-1.2.27.tgz", {}, "sha512-Wk0o/I+Fo+wE3zgvlJDs8Fb67KlKqX0PrV8dK5adSDkANq6r4Z25zXJg2iOir+a8ntg3rAcpel1OY4FV/TwRUA=="],
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.57.1", "", { "os": "linux", "cpu": "arm" }, "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw=="],
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "https://registry.npmmirror.com/@opentelemetry/api/-/api-1.9.0.tgz", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.57.1", "", { "os": "linux", "cpu": "arm" }, "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw=="],
"@paralleldrive/cuid2": ["@paralleldrive/cuid2@3.3.0", "https://registry.npmmirror.com/@paralleldrive/cuid2/-/cuid2-3.3.0.tgz", { "dependencies": { "@noble/hashes": "^2.0.1", "bignumber.js": "^9.3.1", "error-causes": "^3.0.2" }, "bin": { "cuid2": "bin/cuid2.js" } }, "sha512-OqiFvSOF0dBSesELYY2CAMa4YINvlLpvKOz/rv6NeZEqiyttlHgv98Juwv4Ch+GrEV7IZ8jfI2VcEoYUjXXCjw=="],
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.57.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g=="],
"@rollup/plugin-commonjs": ["@rollup/plugin-commonjs@29.0.0", "https://registry.npmmirror.com/@rollup/plugin-commonjs/-/plugin-commonjs-29.0.0.tgz", { "dependencies": { "@rollup/pluginutils": "^5.0.1", "commondir": "^1.0.1", "estree-walker": "^2.0.2", "fdir": "^6.2.0", "is-reference": "1.2.1", "magic-string": "^0.30.3", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^2.68.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-U2YHaxR2cU/yAiwKJtJRhnyLk7cifnQw0zUpISsocBDoHDJn+HTV74ABqnwr5bEgWUwFZC9oFL6wLe21lHu5eQ=="],
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.57.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q=="],
"@rollup/plugin-node-resolve": ["@rollup/plugin-node-resolve@16.0.3", "https://registry.npmmirror.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.3.tgz", { "dependencies": { "@rollup/pluginutils": "^5.0.1", "@types/resolve": "1.20.2", "deepmerge": "^4.2.2", "is-module": "^1.0.0", "resolve": "^1.22.1" }, "peerDependencies": { "rollup": "^2.78.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg=="],
"@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA=="],
"@rollup/plugin-typescript": ["@rollup/plugin-typescript@12.3.0", "https://registry.npmmirror.com/@rollup/plugin-typescript/-/plugin-typescript-12.3.0.tgz", { "dependencies": { "@rollup/pluginutils": "^5.1.0", "resolve": "^1.22.1" }, "peerDependencies": { "rollup": "^2.14.0||^3.0.0||^4.0.0", "tslib": "*", "typescript": ">=3.7.0" }, "optionalPeers": ["rollup", "tslib"] }, "sha512-7DP0/p7y3t67+NabT9f8oTBFE6gGkto4SA6Np2oudYmZE/m1dt8RB0SjL1msMxFpLo631qjRCcBlAbq1ml/Big=="],
"@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw=="],
"@rollup/pluginutils": ["@rollup/pluginutils@5.3.0", "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q=="],
"@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.57.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w=="],
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.57.1", "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", { "os": "android", "cpu": "arm" }, "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg=="],
"@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.57.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw=="],
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.57.1", "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", { "os": "android", "cpu": "arm64" }, "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w=="],
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A=="],
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.57.1", "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", { "os": "darwin", "cpu": "arm64" }, "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg=="],
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw=="],
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.57.1", "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", { "os": "darwin", "cpu": "x64" }, "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w=="],
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.57.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg=="],
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.57.1", "https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", { "os": "freebsd", "cpu": "arm64" }, "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug=="],
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.57.1", "", { "os": "linux", "cpu": "x64" }, "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg=="],
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.57.1", "https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", { "os": "freebsd", "cpu": "x64" }, "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q=="],
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.57.1", "", { "os": "linux", "cpu": "x64" }, "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw=="],
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.57.1", "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", { "os": "linux", "cpu": "arm" }, "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw=="],
"@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.57.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw=="],
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.57.1", "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", { "os": "linux", "cpu": "arm" }, "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw=="],
"@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.57.1", "", { "os": "none", "cpu": "arm64" }, "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ=="],
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.57.1", "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", { "os": "linux", "cpu": "arm64" }, "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g=="],
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.57.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ=="],
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.57.1", "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", { "os": "linux", "cpu": "arm64" }, "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q=="],
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.57.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew=="],
"@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.57.1", "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", { "os": "linux", "cpu": "none" }, "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA=="],
"@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.57.1", "", { "os": "win32", "cpu": "x64" }, "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ=="],
"@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.57.1", "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", { "os": "linux", "cpu": "none" }, "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw=="],
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.57.1", "", { "os": "win32", "cpu": "x64" }, "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA=="],
"@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.57.1", "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", { "os": "linux", "cpu": "ppc64" }, "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w=="],
"@types/bun": ["@types/bun@1.3.9", "", { "dependencies": { "bun-types": "1.3.9" } }, "sha512-KQ571yULOdWJiMH+RIWIOZ7B2RXQGpL1YQrBtLIV3FqDcCu6FsbFUBwhdKUlCKUpS3PJDsHlJ1QKlpxoVR+xtw=="],
"@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.57.1", "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", { "os": "linux", "cpu": "ppc64" }, "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw=="],
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.57.1", "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", { "os": "linux", "cpu": "none" }, "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A=="],
"@types/node": ["@types/node@25.3.0", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A=="],
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.57.1", "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", { "os": "linux", "cpu": "none" }, "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw=="],
"@types/resolve": ["@types/resolve@1.20.2", "", {}, "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="],
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.57.1", "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", { "os": "linux", "cpu": "s390x" }, "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg=="],
"@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="],
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.57.1", "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", { "os": "linux", "cpu": "x64" }, "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg=="],
"anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="],
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.57.1", "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", { "os": "linux", "cpu": "x64" }, "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw=="],
"bun-types": ["bun-types@1.3.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg=="],
"@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.57.1", "https://registry.npmmirror.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", { "os": "openbsd", "cpu": "x64" }, "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw=="],
"chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
"@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.57.1", "https://registry.npmmirror.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", { "os": "none", "cpu": "arm64" }, "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ=="],
"commondir": ["commondir@1.0.1", "", {}, "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg=="],
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.57.1", "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", { "os": "win32", "cpu": "arm64" }, "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ=="],
"cookie-es": ["cookie-es@1.2.2", "", {}, "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg=="],
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.57.1", "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", { "os": "win32", "cpu": "ia32" }, "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew=="],
"crossws": ["crossws@0.3.5", "", { "dependencies": { "uncrypto": "^0.1.3" } }, "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA=="],
"@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.57.1", "https://registry.npmmirror.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", { "os": "win32", "cpu": "x64" }, "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ=="],
"dayjs": ["dayjs@1.11.19", "", {}, "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw=="],
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.57.1", "https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", { "os": "win32", "cpu": "x64" }, "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA=="],
"deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="],
"@standard-schema/spec": ["@standard-schema/spec@1.1.0", "https://registry.npmmirror.com/@standard-schema/spec/-/spec-1.1.0.tgz", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
"defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="],
"@types/bun": ["@types/bun@1.3.10", "https://registry.npmmirror.com/@types/bun/-/bun-1.3.10.tgz", { "dependencies": { "bun-types": "1.3.10" } }, "sha512-0+rlrUrOrTSskibryHbvQkDOWRJwJZqZlxrUs1u4oOoTln8+WIXBPmAuCF35SWB2z4Zl3E84Nl/D0P7803nigQ=="],
"destr": ["destr@2.0.5", "", {}, "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA=="],
"@types/estree": ["@types/estree@1.0.8", "https://registry.npmmirror.com/@types/estree/-/estree-1.0.8.tgz", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
"dotenv": ["dotenv@17.3.1", "", {}, "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA=="],
"@types/node": ["@types/node@25.5.0", "http://mirrors.tencent.com/npm/@types/node/-/node-25.5.0.tgz", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw=="],
"es-toolkit": ["es-toolkit@1.44.0", "", {}, "sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg=="],
"@types/resolve": ["@types/resolve@1.20.2", "https://registry.npmmirror.com/@types/resolve/-/resolve-1.20.2.tgz", {}, "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="],
"estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
"@types/ws": ["@types/ws@8.18.1", "https://registry.npmmirror.com/@types/ws/-/ws-8.18.1.tgz", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="],
"eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="],
"@vercel/oidc": ["@vercel/oidc@3.1.0", "https://registry.npmmirror.com/@vercel/oidc/-/oidc-3.1.0.tgz", {}, "sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w=="],
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
"ai": ["ai@6.0.116", "https://registry.npmmirror.com/ai/-/ai-6.0.116.tgz", { "dependencies": { "@ai-sdk/gateway": "3.0.66", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.19", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-7yM+cTmyRLeNIXwt4Vj+mrrJgVQ9RMIW5WO0ydoLoYkewIvsMcvUmqS4j2RJTUXaF1HphwmSKUMQ/HypNRGOmA=="],
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"anymatch": ["anymatch@3.1.3", "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="],
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
"bignumber.js": ["bignumber.js@9.3.1", "https://registry.npmmirror.com/bignumber.js/-/bignumber.js-9.3.1.tgz", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="],
"h3": ["h3@1.15.5", "", { "dependencies": { "cookie-es": "^1.2.2", "crossws": "^0.3.5", "defu": "^6.1.4", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.4", "radix3": "^1.1.2", "ufo": "^1.6.3", "uncrypto": "^0.1.3" } }, "sha512-xEyq3rSl+dhGX2Lm0+eFQIAzlDN6Fs0EcC4f7BNUmzaRX/PTzeuM+Tr2lHB8FoXggsQIeXLj8EDVgs5ywxyxmg=="],
"bun-types": ["bun-types@1.3.10", "https://registry.npmmirror.com/bun-types/-/bun-types-1.3.10.tgz", { "dependencies": { "@types/node": "*" } }, "sha512-tcpfCCl6XWo6nCVnpcVrxQ+9AYN1iqMIzgrSKYMB/fjLtV2eyAVEg7AxQJuCq/26R6HpKWykQXuSOq/21RYcbg=="],
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
"chokidar": ["chokidar@5.0.0", "https://registry.npmmirror.com/chokidar/-/chokidar-5.0.0.tgz", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
"iron-webcrypto": ["iron-webcrypto@1.2.1", "", {}, "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg=="],
"commander": ["commander@14.0.3", "https://registry.npmmirror.com/commander/-/commander-14.0.3.tgz", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="],
"is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="],
"commondir": ["commondir@1.0.1", "https://registry.npmmirror.com/commondir/-/commondir-1.0.1.tgz", {}, "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg=="],
"is-module": ["is-module@1.0.0", "", {}, "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g=="],
"cookie-es": ["cookie-es@1.2.2", "https://registry.npmmirror.com/cookie-es/-/cookie-es-1.2.2.tgz", {}, "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg=="],
"is-reference": ["is-reference@1.2.1", "", { "dependencies": { "@types/estree": "*" } }, "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ=="],
"crossws": ["crossws@0.3.5", "https://registry.npmmirror.com/crossws/-/crossws-0.3.5.tgz", { "dependencies": { "uncrypto": "^0.1.3" } }, "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA=="],
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
"crypto-js": ["crypto-js@4.2.0", "http://mirrors.tencent.com/npm/crypto-js/-/crypto-js-4.2.0.tgz", {}, "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="],
"lru-cache": ["lru-cache@11.2.6", "", {}, "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ=="],
"dayjs": ["dayjs@1.11.20", "http://mirrors.tencent.com/npm/dayjs/-/dayjs-1.11.20.tgz", {}, "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ=="],
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
"deepmerge": ["deepmerge@4.3.1", "https://registry.npmmirror.com/deepmerge/-/deepmerge-4.3.1.tgz", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="],
"nanoid": ["nanoid@5.1.6", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg=="],
"defu": ["defu@6.1.4", "https://registry.npmmirror.com/defu/-/defu-6.1.4.tgz", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="],
"node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="],
"destr": ["destr@2.0.5", "https://registry.npmmirror.com/destr/-/destr-2.0.5.tgz", {}, "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA=="],
"node-mock-http": ["node-mock-http@1.0.4", "", {}, "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ=="],
"dotenv": ["dotenv@17.3.1", "https://registry.npmmirror.com/dotenv/-/dotenv-17.3.1.tgz", {}, "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA=="],
"normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
"error-causes": ["error-causes@3.0.2", "https://registry.npmmirror.com/error-causes/-/error-causes-3.0.2.tgz", {}, "sha512-i0B8zq1dHL6mM85FGoxaJnVtx6LD5nL2v0hlpGdntg5FOSyzQ46c9lmz5qx0xRS2+PWHGOHcYxGIBC5Le2dRMw=="],
"ofetch": ["ofetch@1.5.1", "", { "dependencies": { "destr": "^2.0.5", "node-fetch-native": "^1.6.7", "ufo": "^1.6.1" } }, "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA=="],
"es-toolkit": ["es-toolkit@1.45.1", "https://registry.npmmirror.com/es-toolkit/-/es-toolkit-1.45.1.tgz", {}, "sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw=="],
"path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="],
"estree-walker": ["estree-walker@2.0.2", "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
"eventemitter3": ["eventemitter3@5.0.4", "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-5.0.4.tgz", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="],
"picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
"eventsource-parser": ["eventsource-parser@3.0.6", "https://registry.npmmirror.com/eventsource-parser/-/eventsource-parser-3.0.6.tgz", {}, "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg=="],
"radix3": ["radix3@1.1.2", "", {}, "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="],
"fdir": ["fdir@6.5.0", "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
"readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="],
"fsevents": ["fsevents@2.3.3", "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
"function-bind": ["function-bind@1.1.2", "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
"rollup": ["rollup@4.57.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.57.1", "@rollup/rollup-android-arm64": "4.57.1", "@rollup/rollup-darwin-arm64": "4.57.1", "@rollup/rollup-darwin-x64": "4.57.1", "@rollup/rollup-freebsd-arm64": "4.57.1", "@rollup/rollup-freebsd-x64": "4.57.1", "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", "@rollup/rollup-linux-arm-musleabihf": "4.57.1", "@rollup/rollup-linux-arm64-gnu": "4.57.1", "@rollup/rollup-linux-arm64-musl": "4.57.1", "@rollup/rollup-linux-loong64-gnu": "4.57.1", "@rollup/rollup-linux-loong64-musl": "4.57.1", "@rollup/rollup-linux-ppc64-gnu": "4.57.1", "@rollup/rollup-linux-ppc64-musl": "4.57.1", "@rollup/rollup-linux-riscv64-gnu": "4.57.1", "@rollup/rollup-linux-riscv64-musl": "4.57.1", "@rollup/rollup-linux-s390x-gnu": "4.57.1", "@rollup/rollup-linux-x64-gnu": "4.57.1", "@rollup/rollup-linux-x64-musl": "4.57.1", "@rollup/rollup-openbsd-x64": "4.57.1", "@rollup/rollup-openharmony-arm64": "4.57.1", "@rollup/rollup-win32-arm64-msvc": "4.57.1", "@rollup/rollup-win32-ia32-msvc": "4.57.1", "@rollup/rollup-win32-x64-gnu": "4.57.1", "@rollup/rollup-win32-x64-msvc": "4.57.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A=="],
"fuse.js": ["fuse.js@7.1.0", "https://registry.npmmirror.com/fuse.js/-/fuse.js-7.1.0.tgz", {}, "sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ=="],
"rollup-plugin-dts": ["rollup-plugin-dts@6.3.0", "", { "dependencies": { "magic-string": "^0.30.21" }, "optionalDependencies": { "@babel/code-frame": "^7.27.1" }, "peerDependencies": { "rollup": "^3.29.4 || ^4", "typescript": "^4.5 || ^5.0" } }, "sha512-d0UrqxYd8KyZ6i3M2Nx7WOMy708qsV/7fTHMHxCMCBOAe3V/U7OMPu5GkX8hC+cmkHhzGnfeYongl1IgiooddA=="],
"h3": ["h3@1.15.5", "https://registry.npmmirror.com/h3/-/h3-1.15.5.tgz", { "dependencies": { "cookie-es": "^1.2.2", "crossws": "^0.3.5", "defu": "^6.1.4", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.4", "radix3": "^1.1.2", "ufo": "^1.6.3", "uncrypto": "^0.1.3" } }, "sha512-xEyq3rSl+dhGX2Lm0+eFQIAzlDN6Fs0EcC4f7BNUmzaRX/PTzeuM+Tr2lHB8FoXggsQIeXLj8EDVgs5ywxyxmg=="],
"supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
"hasown": ["hasown@2.0.2", "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"iron-webcrypto": ["iron-webcrypto@1.2.1", "https://registry.npmmirror.com/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz", {}, "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg=="],
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"is-core-module": ["is-core-module@2.16.1", "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.16.1.tgz", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="],
"ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="],
"is-module": ["is-module@1.0.0", "https://registry.npmmirror.com/is-module/-/is-module-1.0.0.tgz", {}, "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g=="],
"uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="],
"is-reference": ["is-reference@1.2.1", "https://registry.npmmirror.com/is-reference/-/is-reference-1.2.1.tgz", { "dependencies": { "@types/estree": "*" } }, "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ=="],
"undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="],
"js-tokens": ["js-tokens@4.0.0", "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
"unstorage": ["unstorage@1.17.4", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^5.0.0", "destr": "^2.0.5", "h3": "^1.15.5", "lru-cache": "^11.2.0", "node-fetch-native": "^1.6.7", "ofetch": "^1.5.1", "ufo": "^1.6.3" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6 || ^7 || ^8", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1 || ^2 || ^3", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw=="],
"json-schema": ["json-schema@0.4.0", "https://registry.npmmirror.com/json-schema/-/json-schema-0.4.0.tgz", {}, "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="],
"ws": ["@kevisual/ws@8.19.0", "", {}, "sha512-jLsL80wBBKkrJZrfk3SQpJ9JA/zREdlUROj7eCkmzqduAWKSI0wVcXuCKf+mLFCHB0Q0Tkh2rgzjSlurt3JQgw=="],
"lru-cache": ["lru-cache@11.2.6", "https://registry.npmmirror.com/lru-cache/-/lru-cache-11.2.6.tgz", {}, "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ=="],
"zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
"magic-string": ["magic-string@0.30.21", "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.21.tgz", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
"@kevisual/ai/@kevisual/query": ["@kevisual/query@0.0.38", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-bfvbSodsZyMfwY+1T2SvDeOCKsT/AaIxlVe0+B1R/fNhlg2MDq2CP0L9HKiFkEm+OXrvXcYDMKPUituVUM5J6Q=="],
"nanoid": ["nanoid@5.1.7", "http://mirrors.tencent.com/npm/nanoid/-/nanoid-5.1.7.tgz", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-ua3NDgISf6jdwezAheMOk4mbE1LXjm1DfMUDMuJf4AqxLFK3ccGpgWizwa5YV7Yz9EpXwEaWoRXSb/BnV0t5dQ=="],
"anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"node-fetch-native": ["node-fetch-native@1.6.7", "https://registry.npmmirror.com/node-fetch-native/-/node-fetch-native-1.6.7.tgz", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="],
"node-mock-http": ["node-mock-http@1.0.4", "https://registry.npmmirror.com/node-mock-http/-/node-mock-http-1.0.4.tgz", {}, "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ=="],
"normalize-path": ["normalize-path@3.0.0", "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
"ofetch": ["ofetch@1.5.1", "https://registry.npmmirror.com/ofetch/-/ofetch-1.5.1.tgz", { "dependencies": { "destr": "^2.0.5", "node-fetch-native": "^1.6.7", "ufo": "^1.6.1" } }, "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA=="],
"path-browserify-esm": ["path-browserify-esm@1.0.6", "https://registry.npmmirror.com/path-browserify-esm/-/path-browserify-esm-1.0.6.tgz", {}, "sha512-9nUwYvvu/yq1PYrUyYCihNWmpzacaRYF6gGbjLWErrZ4MRDWyfPN7RpE8E7tsw8eqBU/rr7mcoTXbS+Vih8uUA=="],
"path-parse": ["path-parse@1.0.7", "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="],
"picocolors": ["picocolors@1.1.1", "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
"picomatch": ["picomatch@4.0.3", "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.3.tgz", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
"radix3": ["radix3@1.1.2", "https://registry.npmmirror.com/radix3/-/radix3-1.1.2.tgz", {}, "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="],
"react": ["react@19.2.4", "https://registry.npmmirror.com/react/-/react-19.2.4.tgz", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="],
"react-dom": ["react-dom@19.2.4", "https://registry.npmmirror.com/react-dom/-/react-dom-19.2.4.tgz", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.4" } }, "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ=="],
"readdirp": ["readdirp@5.0.0", "https://registry.npmmirror.com/readdirp/-/readdirp-5.0.0.tgz", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="],
"resolve": ["resolve@1.22.11", "https://registry.npmmirror.com/resolve/-/resolve-1.22.11.tgz", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
"rollup": ["rollup@4.57.1", "https://registry.npmmirror.com/rollup/-/rollup-4.57.1.tgz", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.57.1", "@rollup/rollup-android-arm64": "4.57.1", "@rollup/rollup-darwin-arm64": "4.57.1", "@rollup/rollup-darwin-x64": "4.57.1", "@rollup/rollup-freebsd-arm64": "4.57.1", "@rollup/rollup-freebsd-x64": "4.57.1", "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", "@rollup/rollup-linux-arm-musleabihf": "4.57.1", "@rollup/rollup-linux-arm64-gnu": "4.57.1", "@rollup/rollup-linux-arm64-musl": "4.57.1", "@rollup/rollup-linux-loong64-gnu": "4.57.1", "@rollup/rollup-linux-loong64-musl": "4.57.1", "@rollup/rollup-linux-ppc64-gnu": "4.57.1", "@rollup/rollup-linux-ppc64-musl": "4.57.1", "@rollup/rollup-linux-riscv64-gnu": "4.57.1", "@rollup/rollup-linux-riscv64-musl": "4.57.1", "@rollup/rollup-linux-s390x-gnu": "4.57.1", "@rollup/rollup-linux-x64-gnu": "4.57.1", "@rollup/rollup-linux-x64-musl": "4.57.1", "@rollup/rollup-openbsd-x64": "4.57.1", "@rollup/rollup-openharmony-arm64": "4.57.1", "@rollup/rollup-win32-arm64-msvc": "4.57.1", "@rollup/rollup-win32-ia32-msvc": "4.57.1", "@rollup/rollup-win32-x64-gnu": "4.57.1", "@rollup/rollup-win32-x64-msvc": "4.57.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A=="],
"rollup-plugin-dts": ["rollup-plugin-dts@6.3.0", "https://registry.npmmirror.com/rollup-plugin-dts/-/rollup-plugin-dts-6.3.0.tgz", { "dependencies": { "magic-string": "^0.30.21" }, "optionalDependencies": { "@babel/code-frame": "^7.27.1" }, "peerDependencies": { "rollup": "^3.29.4 || ^4", "typescript": "^4.5 || ^5.0" } }, "sha512-d0UrqxYd8KyZ6i3M2Nx7WOMy708qsV/7fTHMHxCMCBOAe3V/U7OMPu5GkX8hC+cmkHhzGnfeYongl1IgiooddA=="],
"scheduler": ["scheduler@0.27.0", "https://registry.npmmirror.com/scheduler/-/scheduler-0.27.0.tgz", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
"sonner": ["sonner@2.0.7", "https://registry.npmmirror.com/sonner/-/sonner-2.0.7.tgz", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w=="],
"spark-md5": ["spark-md5@3.0.2", "https://registry.npmmirror.com/spark-md5/-/spark-md5-3.0.2.tgz", {}, "sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw=="],
"supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
"tslib": ["tslib@2.8.1", "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"typescript": ["typescript@5.9.3", "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"ufo": ["ufo@1.6.3", "https://registry.npmmirror.com/ufo/-/ufo-1.6.3.tgz", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="],
"uncrypto": ["uncrypto@0.1.3", "https://registry.npmmirror.com/uncrypto/-/uncrypto-0.1.3.tgz", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="],
"undici-types": ["undici-types@7.18.2", "https://registry.npmmirror.com/undici-types/-/undici-types-7.18.2.tgz", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="],
"unstorage": ["unstorage@1.17.4", "https://registry.npmmirror.com/unstorage/-/unstorage-1.17.4.tgz", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^5.0.0", "destr": "^2.0.5", "h3": "^1.15.5", "lru-cache": "^11.2.0", "node-fetch-native": "^1.6.7", "ofetch": "^1.5.1", "ufo": "^1.6.3" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6 || ^7 || ^8", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1 || ^2 || ^3", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw=="],
"ws": ["@kevisual/ws@8.19.0", "https://registry.npmmirror.com/@kevisual/ws/-/ws-8.19.0.tgz", {}, "sha512-jLsL80wBBKkrJZrfk3SQpJ9JA/zREdlUROj7eCkmzqduAWKSI0wVcXuCKf+mLFCHB0Q0Tkh2rgzjSlurt3JQgw=="],
"zod": ["zod@4.3.6", "https://registry.npmmirror.com/zod/-/zod-4.3.6.tgz", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
"zustand": ["zustand@5.0.11", "https://registry.npmmirror.com/zustand/-/zustand-5.0.11.tgz", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-fdZY+dk7zn/vbWNCYmzZULHRrss0jx5pPFiOuMZ/5HJN6Yv3u+1Wswy/4MpZEkEGhtNH+pwxZB8OKgUBPzYAGg=="],
"@types/ws/@types/node": ["@types/node@25.3.0", "https://registry.npmmirror.com/@types/node/-/node-25.3.0.tgz", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A=="],
"anymatch/picomatch": ["picomatch@2.3.1", "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"bun-types/@types/node": ["@types/node@25.3.5", "https://registry.npmmirror.com/@types/node/-/node-25.3.5.tgz", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-oX8xrhvpiyRCQkG1MFchB09f+cXftgIXb3a7UUa4Y3wpmZPw5tyZGTLWhlESOLq1Rq6oDlc8npVU2/9xiCuXMA=="],
}
}

1
mod.ts
View File

@@ -1 +0,0 @@
export * from './src/index.ts'

View File

@@ -1,39 +1,53 @@
{
"name": "@kevisual/cnb",
"version": "0.0.37",
"version": "0.0.51",
"description": "",
"main": "index.js",
"basename": "/root/cnb",
"app": {
"type": "system-app",
"entry": "./dist/routes.js",
"engine": "bun"
},
"scripts": {
"build": "bun bun.config.ts",
"flow": "ev npm patch && pnpm build && ev npm publish npm -p"
"flow": "ev npm patch && pnpm build && ev npm publish npm -p",
"compile": "bun build --compile --minify agent/commander.ts --outfile=./dist/cnb ",
"pub": "ev pack -u -m false -c -p"
},
"keywords": [],
"bin": {
"cnb": "./bin/index.js"
"cnb": "bin/index.js",
"cloud": "bin/index.js",
"cloud-npc": "bin/npc.js"
},
"files": [
"dist",
"src",
"mod.ts",
"agent"
],
"author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
"license": "MIT",
"packageManager": "pnpm@10.30.3",
"packageManager": "pnpm@10.32.1",
"type": "module",
"devDependencies": {
"@kevisual/ai": "^0.0.26",
"@ai-sdk/openai-compatible": "^2.0.35",
"@kevisual/ai": "^0.0.28",
"@kevisual/api": "^0.0.64",
"@kevisual/code-builder": "^0.0.6",
"@kevisual/context": "^0.0.8",
"@kevisual/dts": "^0.0.4",
"@kevisual/remote-app": "^0.0.7",
"@kevisual/types": "^0.0.12",
"@opencode-ai/plugin": "^1.2.20",
"@opencode-ai/plugin": "^1.2.27",
"@types/bun": "^1.3.10",
"@types/node": "^25.3.5",
"@types/node": "^25.5.0",
"@types/ws": "^8.18.1",
"ai": "^6.0.116",
"commander": "^14.0.3",
"dayjs": "^1.11.19",
"dotenv": "^17.3.1"
"dayjs": "^1.11.20",
"dotenv": "^17.3.1",
"zod": "^4.3.6"
},
"publishConfig": {
"access": "public"
@@ -43,16 +57,16 @@
},
"dependencies": {
"@kevisual/query": "^0.0.53",
"@kevisual/router": "^0.0.88",
"@kevisual/router": "^0.1.2",
"@kevisual/use-config": "^1.0.30",
"@opencode-ai/sdk": "^1.2.27",
"es-toolkit": "^1.45.1",
"nanoid": "^5.1.6",
"nanoid": "^5.1.7",
"unstorage": "^1.17.4",
"ws": "npm:@kevisual/ws",
"zod": "^4.3.6"
"ws": "npm:@kevisual/ws"
},
"exports": {
".": "./mod.ts",
".": "./src/index.ts",
"./opencode": "./dist/opencode.js",
"./keep": "./dist/keep.js",
"./keep.ts": "./src/keep.ts",

337
pnpm-lock.yaml generated
View File

@@ -15,11 +15,14 @@ importers:
specifier: ^0.0.53
version: 0.0.53
'@kevisual/router':
specifier: ^0.0.88
version: 0.0.88
specifier: ^0.1.1
version: 0.1.1
'@kevisual/use-config':
specifier: ^1.0.30
version: 1.0.30(dotenv@17.3.1)
'@opencode-ai/sdk':
specifier: ^1.2.25
version: 1.2.25
es-toolkit:
specifier: ^1.45.1
version: 1.45.1
@@ -36,9 +39,15 @@ importers:
specifier: ^4.3.6
version: 4.3.6
devDependencies:
'@ai-sdk/openai-compatible':
specifier: ^2.0.35
version: 2.0.35(zod@4.3.6)
'@kevisual/ai':
specifier: ^0.0.26
version: 0.0.26
specifier: ^0.0.28
version: 0.0.28
'@kevisual/api':
specifier: ^0.0.64
version: 0.0.64(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
'@kevisual/code-builder':
specifier: ^0.0.6
version: 0.0.6
@@ -48,33 +57,73 @@ importers:
'@kevisual/dts':
specifier: ^0.0.4
version: 0.0.4(typescript@5.9.3)
'@kevisual/remote-app':
specifier: ^0.0.7
version: 0.0.7
'@kevisual/types':
specifier: ^0.0.12
version: 0.0.12
'@opencode-ai/plugin':
specifier: ^1.2.20
version: 1.2.20
specifier: ^1.2.25
version: 1.2.25
'@types/bun':
specifier: ^1.3.10
version: 1.3.10
'@types/node':
specifier: ^25.3.5
version: 25.3.5
specifier: ^25.5.0
version: 25.5.0
'@types/ws':
specifier: ^8.18.1
version: 8.18.1
ai:
specifier: ^6.0.116
version: 6.0.116(zod@4.3.6)
commander:
specifier: ^14.0.3
version: 14.0.3
dayjs:
specifier: ^1.11.19
version: 1.11.19
specifier: ^1.11.20
version: 1.11.20
dotenv:
specifier: ^17.3.1
version: 17.3.1
packages:
'@ai-sdk/anthropic@3.0.58':
resolution: {integrity: sha512-/53SACgmVukO4bkms4dpxpRlYhW8Ct6QZRe6sj1Pi5H00hYhxIrqfiLbZBGxkdRvjsBQeP/4TVGsXgH5rQeb8Q==}
engines: {node: '>=18'}
peerDependencies:
zod: ^4.3.6
'@ai-sdk/gateway@3.0.66':
resolution: {integrity: sha512-SIQ0YY0iMuv+07HLsZ+bB990zUJ6S4ujORAh+Jv1V2KGNn73qQKnGO0JBk+w+Res8YqOFSycwDoWcFlQrVxS4A==}
engines: {node: '>=18'}
peerDependencies:
zod: ^4.3.6
'@ai-sdk/openai-compatible@2.0.35':
resolution: {integrity: sha512-g3wA57IAQFb+3j4YuFndgkUdXyRETZVvbfAWM+UX7bZSxA3xjes0v3XKgIdKdekPtDGsh4ZX2byHD0gJIMPfiA==}
engines: {node: '>=18'}
peerDependencies:
zod: ^4.3.6
'@ai-sdk/openai@3.0.41':
resolution: {integrity: sha512-IZ42A+FO+vuEQCVNqlnAPYQnnUpUfdJIwn1BEDOBywiEHa23fw7PahxVtlX9zm3/zMvTW4JKPzWyvAgDu+SQ2A==}
engines: {node: '>=18'}
peerDependencies:
zod: ^4.3.6
'@ai-sdk/provider-utils@4.0.19':
resolution: {integrity: sha512-3eG55CrSWCu2SXlqq2QCsFjo3+E7+Gmg7i/oRVoSZzIodTuDSfLb3MRje67xE9RFea73Zao7Lm4mADIfUETKGg==}
engines: {node: '>=18'}
peerDependencies:
zod: ^4.3.6
'@ai-sdk/provider@3.0.8':
resolution: {integrity: sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ==}
engines: {node: '>=18'}
'@babel/code-frame@7.29.0':
resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==}
engines: {node: '>=6.9.0'}
@@ -86,8 +135,11 @@ packages:
'@jridgewell/sourcemap-codec@1.5.5':
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
'@kevisual/ai@0.0.26':
resolution: {integrity: sha512-lhaMpxi+vgqPdyBKiuNbSil4hy13tNLbDiqCtG0qUXKtvoowK6xMx269pSSYkYBivczM8g8I0XEouuJceUpJPg==}
'@kevisual/ai@0.0.28':
resolution: {integrity: sha512-GLwCNXfopDvOj+hEZwEIwOV2/3VGd+TCPgBClaYuAv30KzhgehlCW05HPjBducSg+uPcdKacEzZsecHjo5fMUQ==}
'@kevisual/api@0.0.64':
resolution: {integrity: sha512-y7wP8ucvi/rflVGd6uJpvuEUTwI7wMef8+ITQzv4flg7a2pwWZYe/DT0TOyaqDAqKOTlXaVIdBeI15jXuUxIIg==}
'@kevisual/code-builder@0.0.6':
resolution: {integrity: sha512-0aqATB31/yw4k4s5/xKnfr4DKbUnx8e3Z3BmKbiXTrc+CqWiWTdlGe9bKI9dZ2Df+xNp6g11W4xM2NICNyyCCw==}
@@ -100,6 +152,9 @@ packages:
resolution: {integrity: sha512-FVUaH/0nyhbHWpEVjFTGP54PLMm4Hf06aqWLdHOYHNPIgr1aK1C26kOH7iumklGFGk9w93IGxj8Zxe5fap5N2A==}
hasBin: true
'@kevisual/js-filter@0.0.6':
resolution: {integrity: sha512-FcbOsmS1inhwrfgXMM/XLFTGTHUxBCss32JEMYdEFWQDYCar5rN8cxD1W8FuKDTVRlpA+zBpQ/BE6XT4UaeljA==}
'@kevisual/load@0.0.6':
resolution: {integrity: sha512-+3YTFehRcZ1haGel5DKYMUwmi5i6f2psyaPZlfkKU/cOXgkpwoG9/BEqPCnPjicKqqnksEpixVRkyHJ+5bjLVA==}
@@ -109,14 +164,14 @@ packages:
'@kevisual/permission@0.0.4':
resolution: {integrity: sha512-zwBYPnT/z21W4q2wkklJrxvoYBYWG/+a3iXFDKqXQAnDOcxm/SU1f1N6FQb9KxGKl36/fclVlhxlxqszvKCenQ==}
'@kevisual/query@0.0.52':
resolution: {integrity: sha512-m1UbyDTIxtfAQXM+EqhXA4ytE2V8rV8mXTZVBwzfW9O6+gtvAcRY7K1YYxfewTSXLVh9nwvfHe0KQ8MDL5ukyw==}
'@kevisual/query@0.0.53':
resolution: {integrity: sha512-PAhpCLBr0emz0lGNlTVHMbJiC5wrtGLbInPddRzgKE35fiyNt+SWSsUWABiD0DeNrLN/OxWyAFobt880Z/e5MQ==}
'@kevisual/router@0.0.88':
resolution: {integrity: sha512-T8kEbxyTGxZpbxAKDplDjZMIY+HCnXOeEdjwQ11AQetrLuqLFDZS5PnaWdVAHnONUDLhYoftkNj7bGWLtyQDlg==}
'@kevisual/remote-app@0.0.7':
resolution: {integrity: sha512-d0P8uyxoMnmyT8x1J9XC9ecDBbqW+jOP0ZM5fCgQRDUhWw35V/MnbCD4hNG4b6EmvoiS6a/PBC7RC5JGm3wpCg==}
'@kevisual/router@0.1.1':
resolution: {integrity: sha512-+uaJc+Bf/T1mfxyfy9PmwuxJGPOLhVqrmsli2xUPqkkFvizrFIGB1vBTITuo5XP/FnwGqxgbjsitG57AMubm3w==}
'@kevisual/types@0.0.12':
resolution: {integrity: sha512-zJXH2dosir3jVrQ6QG4i0+iLQeT9gJ3H+cKXs8ReWboxBSYzUZO78XssVeVrFPsJ33iaAqo4q3DWbSS1dWGn7Q==}
@@ -130,11 +185,23 @@ packages:
resolution: {integrity: sha512-jLsL80wBBKkrJZrfk3SQpJ9JA/zREdlUROj7eCkmzqduAWKSI0wVcXuCKf+mLFCHB0Q0Tkh2rgzjSlurt3JQgw==}
engines: {node: '>=10.0.0'}
'@opencode-ai/plugin@1.2.20':
resolution: {integrity: sha512-BE6TOXVxgF24g5QgtlogSY5B+/AmZJ3cYaVjHZhUVuAli9JEg4RblrbrK2rfgbyZBoZDpjBLGTYtIRTVmOccEA==}
'@noble/hashes@2.0.1':
resolution: {integrity: sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==}
engines: {node: '>= 20.19.0'}
'@opencode-ai/sdk@1.2.20':
resolution: {integrity: sha512-U5ROpG21D8jg9rkc1IgKAk1g5dn6X/rkOBfveupd0peSDO9n6VM9aikYccVLaMObxVqdjtG08IeQOFTPVS8ySQ==}
'@opencode-ai/plugin@1.2.25':
resolution: {integrity: sha512-IQnjkcN7cvI/zoiDNx1d2qnGzn5BR/Bu95Kq05/vdd8oX4ARgYkqfaJgKkNSpjUVoNBKHTd8m9q1TtzuKlyGUg==}
'@opencode-ai/sdk@1.2.25':
resolution: {integrity: sha512-ikuGWob48OM7LTgfXFqGOZKVOqh50FEjvtIBhXGhGowJhifmjZ+xuq/ypP8nPjTwUX73pbu1C3X9ZBWVkCN9mA==}
'@opentelemetry/api@1.9.0':
resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==}
engines: {node: '>=8.0.0'}
'@paralleldrive/cuid2@3.3.0':
resolution: {integrity: sha512-OqiFvSOF0dBSesELYY2CAMa4YINvlLpvKOz/rv6NeZEqiyttlHgv98Juwv4Ch+GrEV7IZ8jfI2VcEoYUjXXCjw==}
hasBin: true
'@rollup/plugin-commonjs@29.0.0':
resolution: {integrity: sha512-U2YHaxR2cU/yAiwKJtJRhnyLk7cifnQw0zUpISsocBDoHDJn+HTV74ABqnwr5bEgWUwFZC9oFL6wLe21lHu5eQ==}
@@ -314,14 +381,17 @@ packages:
cpu: [x64]
os: [win32]
'@standard-schema/spec@1.1.0':
resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
'@types/bun@1.3.10':
resolution: {integrity: sha512-0+rlrUrOrTSskibryHbvQkDOWRJwJZqZlxrUs1u4oOoTln8+WIXBPmAuCF35SWB2z4Zl3E84Nl/D0P7803nigQ==}
'@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
'@types/node@25.3.5':
resolution: {integrity: sha512-oX8xrhvpiyRCQkG1MFchB09f+cXftgIXb3a7UUa4Y3wpmZPw5tyZGTLWhlESOLq1Rq6oDlc8npVU2/9xiCuXMA==}
'@types/node@25.5.0':
resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==}
'@types/resolve@1.20.2':
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
@@ -329,10 +399,23 @@ packages:
'@types/ws@8.18.1':
resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
'@vercel/oidc@3.1.0':
resolution: {integrity: sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==}
engines: {node: '>= 20'}
ai@6.0.116:
resolution: {integrity: sha512-7yM+cTmyRLeNIXwt4Vj+mrrJgVQ9RMIW5WO0ydoLoYkewIvsMcvUmqS4j2RJTUXaF1HphwmSKUMQ/HypNRGOmA==}
engines: {node: '>=18'}
peerDependencies:
zod: ^4.3.6
anymatch@3.1.3:
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
engines: {node: '>= 8'}
bignumber.js@9.3.1:
resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==}
bun-types@1.3.10:
resolution: {integrity: sha512-tcpfCCl6XWo6nCVnpcVrxQ+9AYN1iqMIzgrSKYMB/fjLtV2eyAVEg7AxQJuCq/26R6HpKWykQXuSOq/21RYcbg==}
@@ -353,8 +436,8 @@ packages:
crossws@0.3.5:
resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==}
dayjs@1.11.19:
resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==}
dayjs@1.11.20:
resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==}
deepmerge@4.3.1:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
@@ -370,6 +453,9 @@ packages:
resolution: {integrity: sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==}
engines: {node: '>=12'}
error-causes@3.0.2:
resolution: {integrity: sha512-i0B8zq1dHL6mM85FGoxaJnVtx6LD5nL2v0hlpGdntg5FOSyzQ46c9lmz5qx0xRS2+PWHGOHcYxGIBC5Le2dRMw==}
es-toolkit@1.45.1:
resolution: {integrity: sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw==}
@@ -379,6 +465,13 @@ packages:
eventemitter3@5.0.1:
resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
eventemitter3@5.0.4:
resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==}
eventsource-parser@3.0.6:
resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==}
engines: {node: '>=18.0.0'}
fdir@6.5.0:
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
engines: {node: '>=12.0.0'}
@@ -396,6 +489,10 @@ packages:
function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
fuse.js@7.1.0:
resolution: {integrity: sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==}
engines: {node: '>=10'}
h3@1.15.5:
resolution: {integrity: sha512-xEyq3rSl+dhGX2Lm0+eFQIAzlDN6Fs0EcC4f7BNUmzaRX/PTzeuM+Tr2lHB8FoXggsQIeXLj8EDVgs5ywxyxmg==}
@@ -419,6 +516,9 @@ packages:
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
json-schema@0.4.0:
resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==}
lru-cache@11.2.5:
resolution: {integrity: sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==}
engines: {node: 20 || >=22}
@@ -444,6 +544,9 @@ packages:
ofetch@1.5.1:
resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==}
path-browserify-esm@1.0.6:
resolution: {integrity: sha512-9nUwYvvu/yq1PYrUyYCihNWmpzacaRYF6gGbjLWErrZ4MRDWyfPN7RpE8E7tsw8eqBU/rr7mcoTXbS+Vih8uUA==}
path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
@@ -461,6 +564,15 @@ packages:
radix3@1.1.2:
resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==}
react-dom@19.2.4:
resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==}
peerDependencies:
react: ^19.2.4
react@19.2.4:
resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==}
engines: {node: '>=0.10.0'}
readdirp@5.0.0:
resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==}
engines: {node: '>= 20.19.0'}
@@ -482,6 +594,18 @@ packages:
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
scheduler@0.27.0:
resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
sonner@2.0.7:
resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==}
peerDependencies:
react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
spark-md5@3.0.2:
resolution: {integrity: sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw==}
supports-preserve-symlinks-flag@1.0.0:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
@@ -568,8 +692,62 @@ packages:
zod@4.3.6:
resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
zustand@5.0.11:
resolution: {integrity: sha512-fdZY+dk7zn/vbWNCYmzZULHRrss0jx5pPFiOuMZ/5HJN6Yv3u+1Wswy/4MpZEkEGhtNH+pwxZB8OKgUBPzYAGg==}
engines: {node: '>=12.20.0'}
peerDependencies:
'@types/react': '>=18.0.0'
immer: '>=9.0.6'
react: '>=18.0.0'
use-sync-external-store: '>=1.2.0'
peerDependenciesMeta:
'@types/react':
optional: true
immer:
optional: true
react:
optional: true
use-sync-external-store:
optional: true
snapshots:
'@ai-sdk/anthropic@3.0.58(zod@4.3.6)':
dependencies:
'@ai-sdk/provider': 3.0.8
'@ai-sdk/provider-utils': 4.0.19(zod@4.3.6)
zod: 4.3.6
'@ai-sdk/gateway@3.0.66(zod@4.3.6)':
dependencies:
'@ai-sdk/provider': 3.0.8
'@ai-sdk/provider-utils': 4.0.19(zod@4.3.6)
'@vercel/oidc': 3.1.0
zod: 4.3.6
'@ai-sdk/openai-compatible@2.0.35(zod@4.3.6)':
dependencies:
'@ai-sdk/provider': 3.0.8
'@ai-sdk/provider-utils': 4.0.19(zod@4.3.6)
zod: 4.3.6
'@ai-sdk/openai@3.0.41(zod@4.3.6)':
dependencies:
'@ai-sdk/provider': 3.0.8
'@ai-sdk/provider-utils': 4.0.19(zod@4.3.6)
zod: 4.3.6
'@ai-sdk/provider-utils@4.0.19(zod@4.3.6)':
dependencies:
'@ai-sdk/provider': 3.0.8
'@standard-schema/spec': 1.1.0
eventsource-parser: 3.0.6
zod: 4.3.6
'@ai-sdk/provider@3.0.8':
dependencies:
json-schema: 0.4.0
'@babel/code-frame@7.29.0':
dependencies:
'@babel/helper-validator-identifier': 7.28.5
@@ -582,11 +760,38 @@ snapshots:
'@jridgewell/sourcemap-codec@1.5.5': {}
'@kevisual/ai@0.0.26':
'@kevisual/ai@0.0.28':
dependencies:
'@ai-sdk/anthropic': 3.0.58(zod@4.3.6)
'@ai-sdk/openai': 3.0.41(zod@4.3.6)
'@ai-sdk/openai-compatible': 2.0.35(zod@4.3.6)
'@kevisual/js-filter': 0.0.6
'@kevisual/logger': 0.0.4
'@kevisual/permission': 0.0.4
'@kevisual/query': 0.0.52
'@kevisual/query': 0.0.53
ai: 6.0.116(zod@4.3.6)
zod: 4.3.6
'@kevisual/api@0.0.64(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
dependencies:
'@kevisual/context': 0.0.8
'@kevisual/js-filter': 0.0.6
'@kevisual/load': 0.0.6
'@paralleldrive/cuid2': 3.3.0
es-toolkit: 1.45.1
eventemitter3: 5.0.4
fuse.js: 7.1.0
nanoid: 5.1.6
path-browserify-esm: 1.0.6
sonner: 2.0.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
spark-md5: 3.0.2
zustand: 5.0.11(react@19.2.4)
transitivePeerDependencies:
- '@types/react'
- immer
- react
- react-dom
- use-sync-external-store
'@kevisual/code-builder@0.0.6': {}
@@ -603,6 +808,8 @@ snapshots:
transitivePeerDependencies:
- typescript
'@kevisual/js-filter@0.0.6': {}
'@kevisual/load@0.0.6':
dependencies:
eventemitter3: 5.0.1
@@ -611,11 +818,11 @@ snapshots:
'@kevisual/permission@0.0.4': {}
'@kevisual/query@0.0.52': {}
'@kevisual/query@0.0.53': {}
'@kevisual/router@0.0.88':
'@kevisual/remote-app@0.0.7': {}
'@kevisual/router@0.1.1':
dependencies:
es-toolkit: 1.45.1
@@ -628,12 +835,22 @@ snapshots:
'@kevisual/ws@8.19.0': {}
'@opencode-ai/plugin@1.2.20':
'@noble/hashes@2.0.1': {}
'@opencode-ai/plugin@1.2.25':
dependencies:
'@opencode-ai/sdk': 1.2.20
'@opencode-ai/sdk': 1.2.25
zod: 4.3.6
'@opencode-ai/sdk@1.2.20': {}
'@opencode-ai/sdk@1.2.25': {}
'@opentelemetry/api@1.9.0': {}
'@paralleldrive/cuid2@3.3.0':
dependencies:
'@noble/hashes': 2.0.1
bignumber.js: 9.3.1
error-causes: 3.0.2
'@rollup/plugin-commonjs@29.0.0(rollup@4.57.1)':
dependencies:
@@ -749,13 +966,15 @@ snapshots:
'@rollup/rollup-win32-x64-msvc@4.57.1':
optional: true
'@standard-schema/spec@1.1.0': {}
'@types/bun@1.3.10':
dependencies:
bun-types: 1.3.10
'@types/estree@1.0.8': {}
'@types/node@25.3.5':
'@types/node@25.5.0':
dependencies:
undici-types: 7.18.2
@@ -763,16 +982,28 @@ snapshots:
'@types/ws@8.18.1':
dependencies:
'@types/node': 25.3.5
'@types/node': 25.5.0
'@vercel/oidc@3.1.0': {}
ai@6.0.116(zod@4.3.6):
dependencies:
'@ai-sdk/gateway': 3.0.66(zod@4.3.6)
'@ai-sdk/provider': 3.0.8
'@ai-sdk/provider-utils': 4.0.19(zod@4.3.6)
'@opentelemetry/api': 1.9.0
zod: 4.3.6
anymatch@3.1.3:
dependencies:
normalize-path: 3.0.0
picomatch: 2.3.1
bignumber.js@9.3.1: {}
bun-types@1.3.10:
dependencies:
'@types/node': 25.3.5
'@types/node': 25.5.0
chokidar@5.0.0:
dependencies:
@@ -788,7 +1019,7 @@ snapshots:
dependencies:
uncrypto: 0.1.3
dayjs@1.11.19: {}
dayjs@1.11.20: {}
deepmerge@4.3.1: {}
@@ -798,12 +1029,18 @@ snapshots:
dotenv@17.3.1: {}
error-causes@3.0.2: {}
es-toolkit@1.45.1: {}
estree-walker@2.0.2: {}
eventemitter3@5.0.1: {}
eventemitter3@5.0.4: {}
eventsource-parser@3.0.6: {}
fdir@6.5.0(picomatch@4.0.3):
optionalDependencies:
picomatch: 4.0.3
@@ -813,6 +1050,8 @@ snapshots:
function-bind@1.1.2: {}
fuse.js@7.1.0: {}
h3@1.15.5:
dependencies:
cookie-es: 1.2.2
@@ -844,6 +1083,8 @@ snapshots:
js-tokens@4.0.0:
optional: true
json-schema@0.4.0: {}
lru-cache@11.2.5: {}
magic-string@0.30.21:
@@ -864,6 +1105,8 @@ snapshots:
node-fetch-native: 1.6.7
ufo: 1.6.3
path-browserify-esm@1.0.6: {}
path-parse@1.0.7: {}
picocolors@1.1.1:
@@ -875,6 +1118,13 @@ snapshots:
radix3@1.1.2: {}
react-dom@19.2.4(react@19.2.4):
dependencies:
react: 19.2.4
scheduler: 0.27.0
react@19.2.4: {}
readdirp@5.0.0: {}
resolve@1.22.11:
@@ -922,6 +1172,15 @@ snapshots:
'@rollup/rollup-win32-x64-msvc': 4.57.1
fsevents: 2.3.3
scheduler@0.27.0: {}
sonner@2.0.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
dependencies:
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
spark-md5@3.0.2: {}
supports-preserve-symlinks-flag@1.0.0: {}
tslib@2.8.1: {}
@@ -946,3 +1205,7 @@ snapshots:
ufo: 1.6.3
zod@4.3.6: {}
zustand@5.0.11(react@19.2.4):
optionalDependencies:
react: 19.2.4

View File

@@ -1,5 +1,13 @@
# cnb.cool 能做什么
所有的代码仓库,只基于一个准则 `group/repo`
## 环境变量
```sh
CNB_API_KEY
CNB_COOKIE
```
## 简介
纯粹调用api的模式去使用cnb.cool自动化方案。

View File

@@ -67,4 +67,17 @@ export * from './user/index.ts'
export * from './build/index.ts'
export * from './issue/index.ts'
export * from './mission/index.ts'
export * from './ai/index.ts'
export * from './ai/index.ts'
export const getCNBVersion = () => {
const url = 'https://cnb.cool/api/version';
// {"version":"1.18.8-2e3e01f0-20260309","commitID":"2e3e01f0","hash":"897b088418dccd05"}
return fetch(url).then(res => res.json()) as Promise<VersionInfo>;
}
type VersionInfo = {
version: string;
commitID: string;
hash: string;
}
export * from './issue/npc/env.ts'

View File

@@ -1,16 +1,27 @@
import { CNBCore, CNBCoreOptions, RequestOptions, Result } from "../cnb-core.ts";
import { extractAliveInfo } from "./issue-alive.ts";
import { useNPCEnv, useCommentEnv, usePullRequestEnv, useRepoInfoEnv } from "./npc/env.ts";
export type IssueAssignee = {
nickname: string;
username: string;
};
export type IssueLabel = {
color: string;
description: string;
id: string;
name: string;
creator?: {
username: string;
nickname: string;
email: string;
is_npc: boolean;
};
applied_by?: {
username: string;
nickname: string;
email: string;
is_npc: boolean;
}
};
export type IssueState = 'open' | 'closed';
@@ -22,6 +33,26 @@ export type IssueAuthor = {
ended_at: string;
};
export type IssueCommentUser = {
username: string;
nickname: string;
avatar: string;
is_npc: boolean;
};
export type IssueCommentReaction = {
// 根据实际返回数据补充
};
export type IssueComment = {
id: string;
body: string;
author: IssueCommentUser;
reactions: IssueCommentReaction[];
created_at: string;
updated_at: string;
};
export type IssueItem = {
assignees: IssueAssignee[];
author: IssueAuthor;
@@ -42,14 +73,14 @@ export class Issue extends CNBCore {
super(options);
}
createIssue(repo: string, data: Partial<IssueItem>): Promise<any> {
createIssue(repo: string, data: Partial<IssueItem>): Promise<Result<IssueItem>> {
const url = `/${repo}/-/issues`;
let postData = {
...data,
};
return this.post({ url, data: postData });
}
updateIssue(repo: string, issueNumber: string | number, data: Partial<IssueItem>): Promise<any> {
updateIssue(repo: string, issueNumber: string | number, data: Partial<IssueItem>): Promise<Result<IssueItem>> {
const url = `/${repo}/-/issues/${issueNumber}`;
let postData = {
...data,
@@ -76,10 +107,34 @@ export class Issue extends CNBCore {
}
});
}
getCommentList(repo: string, issueNumber: string | number): Promise<any> {
getCommentList(repo: string, issueNumber: string | number, params?: { page?: number; page_size?: number }): Promise<Result<IssueComment[]>> {
const url = `/${repo}/-/issues/${issueNumber}/comments`;
return this.get({
url,
params,
});
}
getComment(repo: string, issueNumber: string | number, commentId: string | number): Promise<Result<IssueComment>> {
const url = `/${repo}/-/issues/${issueNumber}/comments/${commentId}`;
return this.get({
url,
});
}
createComment(repo: string, issueNumber: string | number, body: string): Promise<Result<IssueComment>> {
const url = `/${repo}/-/issues/${issueNumber}/comments`;
return this.post({
url,
data: { body },
});
}
updateComment(repo: string, issueNumber: string | number, commentId: string | number, body: string): Promise<Result<IssueComment>> {
const url = `/${repo}/-/issues/${issueNumber}/comments/${commentId}`;
return this.patch({
url,
data: { body },
});
}
setIssueProperty(repo: string, issueNumber: string | number, properties: { [key: string]: any }[]): Promise<any> {
@@ -134,6 +189,18 @@ export class Issue extends CNBCore {
},
};
}
useNPCEnv() {
return useNPCEnv();
}
useCommentEnv() {
return useCommentEnv();
}
usePullRequestEnv() {
return usePullRequestEnv();
}
useRepoInfoEnv() {
return useRepoInfoEnv();
}
}
type GetListParams = {

217
src/issue/npc/build-env.ts Normal file
View File

@@ -0,0 +1,217 @@
import { useKey } from "@kevisual/context";
// CNB_BUILD_ID cnb-75b-1jj9hnk99 当前构建的流水号,全局唯一
// CNB_BUILD_WEB_URL https://cnb.cool/kevision/dev-cnb/-/build/logs/cnb-75b-1jj9hnk99 当前构建的日志地址
// CNB_BUILD_START_TIME 2026-03-09T14:59:01.550Z 当前构建的开始时间UTC 格式,示例 2025-08-21T09:13:45.803Z
// CNB_BUILD_USER xiongxiao 当前构建的触发者用户名
// CNB_BUILD_USER_NICKNAME 小熊猫呜呜呜 当前构建的触发者昵称
// CNB_BUILD_USER_EMAIL kevisual@xiongxiao.me 当前构建的触发者邮箱
// CNB_BUILD_USER_ID 1935321989751226368 当前构建的触发者 id
// CNB_BUILD_USER_NPC_SLUG 当前构建若为 NPC 触发,则为 NPC 所属仓库的路径
// CNB_BUILD_USER_NPC_NAME 当前构建若为 NPC 触发,则为 NPC 角色名
// CNB_BUILD_STAGE_NAME 初始化开发机 当前构建的 stage 名称
// CNB_BUILD_JOB_NAME 初始化开发机 当前构建的 job 名称
// CNB_BUILD_JOB_KEY job-0 当前构建的 job key同 stage 下唯一
// CNB_BUILD_WORKSPACE /workspace/ 自定义 shell 脚本执行的工作空间根目录
// CNB_BUILD_FAILED_MSG 流水线构建失败的错误信息,可在 failStages 中使用
// CNB_BUILD_FAILED_STAGE_NAME 流水线构建失败的 stage 的名称,可在 failStages 中使用
// CNB_PIPELINE_NAME pipeline-1 当前 pipeline 的 name没声明时为空
// CNB_PIPELINE_KEY pipeline-1 当前 pipeline 的索引 key例如 pipeline-0
// CNB_PIPELINE_ID cnb-75b-1jj9hnk99-001 当前 pipeline 的 id全局唯一字符串
// CNB_PIPELINE_DOCKER_IMAGE docker.cnb.cool/kevisual/dev-env:latest 当前 pipeline 所使用的 docker imagealpine:latest
// CNB_PIPELINE_STATUS 当前流水线的构建状态,可在 endStages 中查看其可能的值包括success、error、cancel
// CNB_PIPELINE_MAX_RUN_TIME 72000000 流水线最大运行时间,单位为毫秒
// CNB_RUNNER_IP 10.235.16.3 当前 pipeline 所在 Runner 的 ip
// CNB_CPUS 16 当前构建流水线可以使用的最大 CPU 核数
// CNB_MEMORY 32 当前构建流水线可以使用的最大内存大小,单位为 GiB
// CNB_IS_RETRY false 当前构建是否由 rebuild 触发
// HUSKY_SKIP_INSTALL 1 兼容 ci 环境下 husky
export const useBuildEnv = () => {
const buildId = useKey("CNB_BUILD_ID");
const buildWebUrl = useKey("CNB_BUILD_WEB_URL");
const buildStartTime = useKey("CNB_BUILD_START_TIME");
const buildUser = useKey("CNB_BUILD_USER");
const buildUserNickname = useKey("CNB_BUILD_USER_NICKNAME");
const buildUserEmail = useKey("CNB_BUILD_USER_EMAIL");
const buildUserId = useKey("CNB_BUILD_USER_ID");
const buildUserNpcSlug = useKey("CNB_BUILD_USER_NPC_SLUG");
const buildUserNpcName = useKey("CNB_BUILD_USER_NPC_NAME");
const buildStageName = useKey("CNB_BUILD_STAGE_NAME");
const buildJobName = useKey("CNB_BUILD_JOB_NAME");
const buildJobKey = useKey("CNB_BUILD_JOB_KEY");
const buildWorkspace = useKey("CNB_BUILD_WORKSPACE");
const buildFailedMsg = useKey("CNB_BUILD_FAILED_MSG");
const buildFailedStageName = useKey("CNB_BUILD_FAILED_STAGE_NAME");
const pipelineName = useKey("CNB_PIPELINE_NAME");
const pipelineKey = useKey("CNB_PIPELINE_KEY");
const pipelineId = useKey("CNB_PIPELINE_ID");
const pipelineDockerImage = useKey("CNB_PIPELINE_DOCKER_IMAGE");
const pipelineStatus = useKey("CNB_PIPELINE_STATUS");
const pipelineMaxRunTime = useKey("CNB_PIPELINE_MAX_RUN_TIME");
const runnerIp = useKey("CNB_RUNNER_IP");
const cpus = useKey("CNB_CPUS");
const memory = useKey("CNB_MEMORY");
const isRetry = useKey("CNB_IS_RETRY");
const huskySkipInstall = useKey("HUSKY_SKIP_INSTALL");
return {
/**
* @key CNB_BUILD_ID
* @description:当前构建的流水号,全局唯一
*/
buildId,
buildIdLabel: "当前构建的流水号,全局唯一",
/**
* @key CNB_BUILD_WEB_URL
* @description:当前构建的日志地址
*/
buildWebUrl,
buildWebUrlLabel: "当前构建的日志地址",
/**
* @key CNB_BUILD_START_TIME
* @description:当前构建的开始时间UTC 格式
*/
buildStartTime,
buildStartTimeLabel: "当前构建的开始时间UTC 格式",
/**
* @key CNB_BUILD_USER
* @description:当前构建的触发者用户名
*/
buildUser,
buildUserLabel: "当前构建的触发者用户名",
/**
* @key CNB_BUILD_USER_NICKNAME
* @description:当前构建的触发者昵称
*/
buildUserNickname,
buildUserNicknameLabel: "当前构建的触发者昵称",
/**
* @key CNB_BUILD_USER_EMAIL
* @description:当前构建的触发者邮箱
*/
buildUserEmail,
buildUserEmailLabel: "当前构建的触发者邮箱",
/**
* @key CNB_BUILD_USER_ID
* @description:当前构建的触发者 id
*/
buildUserId,
buildUserIdLabel: "当前构建的触发者 id",
/**
* @key CNB_BUILD_USER_NPC_SLUG
* @description:当前构建若为 NPC 触发,则为 NPC 所属仓库的路径
*/
buildUserNpcSlug,
buildUserNpcSlugLabel: "当前构建若为 NPC 触发,则为 NPC 所属仓库的路径",
/**
* @key CNB_BUILD_USER_NPC_NAME
* @description:当前构建若为 NPC 触发,则为 NPC 角色名
*/
buildUserNpcName,
buildUserNpcNameLabel: "当前构建若为 NPC 触发,则为 NPC 角色名",
/**
* @key CNB_BUILD_STAGE_NAME
* @description:当前构建的 stage 名称
*/
buildStageName,
buildStageNameLabel: "当前构建的 stage 名称",
/**
* @key CNB_BUILD_JOB_NAME
* @description:当前构建的 job 名称
*/
buildJobName,
buildJobNameLabel: "当前构建的 job 名称",
/**
* @key CNB_BUILD_JOB_KEY
* @description:当前构建的 job key同 stage 下唯一
*/
buildJobKey,
buildJobKeyLabel: "当前构建的 job key同 stage 下唯一",
/**
* @key CNB_BUILD_WORKSPACE
* @description:自定义 shell 脚本执行的工作空间根目录
*/
buildWorkspace,
buildWorkspaceLabel: "自定义 shell 脚本执行的工作空间根目录",
/**
* @key CNB_BUILD_FAILED_MSG
* @description:流水线构建失败的错误信息
*/
buildFailedMsg,
buildFailedMsgLabel: "流水线构建失败的错误信息",
/**
* @key CNB_BUILD_FAILED_STAGE_NAME
* @description:流水线构建失败的 stage 的名称
*/
buildFailedStageName,
buildFailedStageNameLabel: "流水线构建失败的 stage 的名称",
/**
* @key CNB_PIPELINE_NAME
* @description:当前 pipeline 的 name
*/
pipelineName,
pipelineNameLabel: "当前 pipeline 的 name",
/**
* @key CNB_PIPELINE_KEY
* @description:当前 pipeline 的索引 key
*/
pipelineKey,
pipelineKeyLabel: "当前 pipeline 的索引 key",
/**
* @key CNB_PIPELINE_ID
* @description:当前 pipeline 的 id
*/
pipelineId,
pipelineIdLabel: "当前 pipeline 的 id",
/**
* @key CNB_PIPELINE_DOCKER_IMAGE
* @description:当前 pipeline 所使用的 docker image
*/
pipelineDockerImage,
pipelineDockerImageLabel: "当前 pipeline 所使用的 docker image",
/**
* @key CNB_PIPELINE_STATUS
* @description:当前流水线的构建状态可能的值包括success、error、cancel
*/
pipelineStatus,
pipelineStatusLabel: "当前流水线的构建状态可能的值包括success、error、cancel",
/**
* @key CNB_PIPELINE_MAX_RUN_TIME
* @description:流水线最大运行时间,单位为毫秒
*/
pipelineMaxRunTime,
pipelineMaxRunTimeLabel: "流水线最大运行时间,单位为毫秒",
/**
* @key CNB_RUNNER_IP
* @description:当前 pipeline 所在 Runner 的 ip
*/
runnerIp,
runnerIpLabel: "当前 pipeline 所在 Runner 的 ip",
/**
* @key CNB_CPUS
* @description:当前构建流水线可以使用的最大 CPU 核数
*/
cpus,
cpusLabel: "当前构建流水线可以使用的最大 CPU 核数",
/**
* @key CNB_MEMORY
* @description:当前构建流水线可以使用的最大内存大小,单位为 GiB
*/
memory,
memoryLabel: "当前构建流水线可以使用的最大内存大小,单位为 GiB",
/**
* @key CNB_IS_RETRY
* @description:当前构建是否由 rebuild 触发
*/
isRetry,
isRetryLabel: "当前构建是否由 rebuild 触发",
/**
* @key HUSKY_SKIP_INSTALL
* @description:兼容 ci 环境下 husky
*/
huskySkipInstall,
huskySkipInstallLabel: "兼容 ci 环境下 husky"
};
}

201
src/issue/npc/env.ts Normal file
View File

@@ -0,0 +1,201 @@
// CNB_NPC_SLUG 对于 @ 知识库角色触发的 NPC 事件,值为 NPC 所属仓库路径,否则为空字符串
// CNB_NPC_NAME 对于 NPC 事件触发的构建,值为 NPC 角色名,否则为空字符串
// CNB_NPC_SHA 对于 @ 知识库角色触发的 NPC 事件,值为 NPC 所属仓库默认分支最新提交的 sha否则为空字符串
// CNB_NPC_PROMPT 对于 @ 知识库角色触发的 NPC 事件,值为 NPC 角色 Prompt否则为空字符串
// CNB_NPC_AVATAR 对于 @ 知识库角色触发的 NPC 事件,值为 NPC 角色头像,否则为空字符串
// CNB_NPC_ENABLE_THINKING 对于 @npc 事件触发的构建,值为 NPC 角色是否开启思考,否则为空字符串
import { useKey } from "@kevisual/context";
export function useNPCEnv() {
const npcSlug = useKey("CNB_NPC_SLUG");
const npcName = useKey("CNB_NPC_NAME");
const npcSha = useKey("CNB_NPC_SHA");
const npcPrompt = useKey("CNB_NPC_PROMPT");
const npcAvatar = useKey("CNB_NPC_AVATAR");
const npcEnableThinking = useKey("CNB_NPC_ENABLE_THINKING");
return {
/**
* @key CNB_NPC_SLUG
* @description:对于 @ 知识库角色触发的 NPC 事件,值为 NPC 所属仓库路径,否则为空字符串
*/
npcSlug,
npcSlugLabel: "对于 @ 知识库角色触发的 NPC 事件,值为 NPC 所属仓库路径,否则为空字符串",
/**
* @key CNB_NPC_NAME
* @description:对于 NPC 事件触发的构建,值为 NPC 角色名,否则为空字符串
*/
npcName,
npcNameLabel: "对于 NPC 事件触发的构建,值为 NPC 角色名,否则为空字符串",
/**
* @key CNB_NPC_SHA
* @description:对于 @ 知识库角色触发的 NPC 事件,值为 NPC 所属仓库默认分支最新提交的 sha否则为空字符串
*/
npcSha,
npcShaLabel: "对于 @ 知识库角色触发的 NPC 事件,值为 NPC 所属仓库默认分支最新提交的 sha否则为空字符串",
/**
* @key CNB_NPC_PROMPT
* @description:对于 @ 知识库角色触发的 NPC 事件,值为 NPC 角色 Prompt否则为空字符串
*/
npcPrompt,
npcPromptLabel: "对于 @ 知识库角色触发的 NPC 事件,值为 NPC 角色 Prompt否则为空字符串",
/**
* @key CNB_NPC_AVATAR
* @description:对于 @ 知识库角色触发的 NPC 事件,值为 NPC 角色头像,否则为空字符串
*/
npcAvatar,
npcAvatarLabel: "对于 @ 知识库角色触发的 NPC 事件,值为 NPC 角色头像,否则为空字符串",
/**
* @key CNB_NPC_ENABLE_THINKING
* @description:对于 @npc 事件触发的构建,值为 NPC 角色是否开启思考,否则为空字符串
*/
npcEnableThinking,
npcEnableThinkingLabel: "对于 @npc 事件触发的构建,值为 NPC 角色是否开启思考,否则为空字符串"
};
}
// CNB_COMMENT_ID 对于评论事件触发的构建,值为评论全局唯一 ID否则为空字符串
// CNB_COMMENT_BODY 对于评论事件触发的构建,值为评论内容,否则为空字符串
// CNB_COMMENT_TYPE note 对于 PR 代码评审评论,值为 diff_note对于 PR 非代码评审评论以及 Issue 评论,值为 note否则为空字符串
// CNB_COMMENT_FILE_PATH 对于 PR 代码评审评论,值为评论所在文件,否则为空字符串
// CNB_COMMENT_RANGE 对于 PR 代码评审评论,值为评论所在代码行。如,单行为 L12多行为 L13-L16否则为空字符串
// CNB_REVIEW_ID 对于 PR 代码评审,值为评审 ID否则为空字符串
export function useCommentEnv() {
const commentId = useKey("CNB_COMMENT_ID");
const commentBody = useKey("CNB_COMMENT_BODY");
const commentType = useKey("CNB_COMMENT_TYPE");
const commentFilePath = useKey("CNB_COMMENT_FILE_PATH");
const commentRange = useKey("CNB_COMMENT_RANGE");
const reviewId = useKey("CNB_REVIEW_ID");
return {
/**
* @key CNB_COMMENT_ID
* @description:对于评论事件触发的构建,值为评论全局唯一 ID否则为空字符串
*/
commentId,
commentIdLabel: "对于评论事件触发的构建,值为评论全局唯一 ID否则为空字符串",
/**
* @key CNB_COMMENT_BODY
* @description:对于评论事件触发的构建,值为评论内容,否则为空字符串
*/
commentBody,
commentBodyLabel: "对于评论事件触发的构建,值为评论内容,否则为空字符串",
/**
* @key CNB_COMMENT_TYPE
* @description:note 对于 PR 代码评审评论,值为 diff_note对于 PR 非代码评审评论以及 Issue 评论,值为 note否则为空字符串
*/
commentType,
commentTypeLabel: "对于 PR 代码评审评论,值为 diff_note对于 PR 非代码评审评论以及 Issue 评论,值为 note否则为空字符串",
/**
* @key CNB_COMMENT_FILE_PATH
* @description:对于 PR 代码评审评论,值为评论所在文件,否则为空字符串
*/
commentFilePath,
commentFilePathLabel: "对于 PR 代码评审评论,值为评论所在文件,否则为空字符串",
/**
* @key CNB_COMMENT_RANGE
* @description:对于 PR 代码评审评论,值为评论所在代码行。如,单行为 L12多行为 L13-L16否则为空字符串
*/
commentRange,
commentRangeLabel: "对于 PR 代码评审评论,值为评论所在代码行。如,单行为 L12多行为 L13-L16否则为空字符串",
/**
* @key CNB_REVIEW_ID
* @description:对于 PR 代码评审,值为评审 ID否则为空字符串
*/
reviewId,
reviewIdLabel: "对于 PR 代码评审,值为评审 ID否则为空字符串"
};
}
// CNB_ISSUE_ID Issue 全局唯一 ID
// CNB_ISSUE_IID Issue 仓库编号
// CNB_ISSUE_TITLE Issue 标题
// CNB_ISSUE_DESCRIPTION Issue 描述
// CNB_ISSUE_OWNER Issue 作者
// CNB_ISSUE_STATE Issue 状态
// CNB_ISSUE_IS_RESOLVED Issue 是否已解决
// CNB_ISSUE_ASSIGNEES Issue 处理人列表
// CNB_ISSUE_LABELS Issue 标签列表
// CNB_ISSUE_PRIORITY Issue 优先级
export const useIssueEnv = () => {
const issueId = useKey("CNB_ISSUE_ID");
const issueIid = useKey("CNB_ISSUE_IID");
const issueTitle = useKey("CNB_ISSUE_TITLE");
const issueDescription = useKey("CNB_ISSUE_DESCRIPTION");
const issueOwner = useKey("CNB_ISSUE_OWNER");
const issueState = useKey("CNB_ISSUE_STATE");
const issueIsResolved = useKey("CNB_ISSUE_IS_RESOLVED");
const issueAssignees = useKey("CNB_ISSUE_ASSIGNEES");
const issueLabels = useKey("CNB_ISSUE_LABELS");
const issuePriority = useKey("CNB_ISSUE_PRIORITY");
return {
/**
* @key CNB_ISSUE_ID
* @description:Issue 全局唯一 ID
*/
issueId,
issueIdLabel: "Issue 全局唯一 ID",
/**
* @key CNB_ISSUE_IID
* @description:Issue 仓库编号
*/
issueIid,
issueIidLabel: "Issue 仓库编号",
/**
* @key CNB_ISSUE_TITLE
* @description:Issue 标题
*/
issueTitle,
issueTitleLabel: "Issue 标题",
/**
* @key CNB_ISSUE_DESCRIPTION
* @description:Issue 描述
*/
issueDescription,
issueDescriptionLabel: "Issue 描述",
/**
* @key CNB_ISSUE_OWNER
* @description:Issue 作者
*/
issueOwner,
issueOwnerLabel: "Issue 作者",
/**
* @key CNB_ISSUE_STATE
* @description:Issue 状态
*/
issueState,
issueStateLabel: "Issue 状态",
/**
* @key CNB_ISSUE_IS_RESOLVED
* @description:Issue 是否已解决
*/
issueIsResolved,
issueIsResolvedLabel: "Issue 是否已解决",
/**
* @key CNB_ISSUE_ASSIGNEES
* @description:Issue 处理人列表
*/
issueAssignees,
issueAssigneesLabel: "Issue 处理人列表",
/**
* @key CNB_ISSUE_LABELS
* @description:Issue 标签列表, 多个以 , 分隔。
*/
issueLabels,
issueLabelsLabel: "Issue 标签列表, 多个以 , 分隔。",
/**
* @key CNB_ISSUE_PRIORITY
* @description:Issue 优先级
*/
issuePriority,
issuePriorityLabel: "Issue 优先级"
};
}
export * from './build-env.ts'
export * from './pr-env.ts'
export * from './repo-env.ts'

95
src/issue/npc/pr-env.ts Normal file
View File

@@ -0,0 +1,95 @@
import { useKey } from "@kevisual/context";
// CNB_PULL_REQUEST false 对于由 pull_request、pull_request.update、pull_request.target 触发的构建,值为 true否则为 false
// CNB_PULL_REQUEST_LIKE false 对于由 合并类事件 触发的构建,值为 true否则为 false
// CNB_PULL_REQUEST_PROPOSER 对于由 合并类事件 触发的构建,值为提出 PR 者名称,否则为空字符串
// CNB_PULL_REQUEST_TITLE 对于由 合并类事件 触发的构建,值为提 PR 时候填写的标题,否则为空字符串
// CNB_PULL_REQUEST_BRANCH 对于由 合并类事件 触发的构建,值为发起 PR 的源分支名称,否则为空字符串
// CNB_PULL_REQUEST_SHA 对于由 合并类事件 触发的构建,值为当前 PR 源分支最新的提交 sha否则为空字符串
// CNB_PULL_REQUEST_TARGET_SHA 对于由 合并类事件 触发的构建,值为当前 PR 目标分支最新的提交 sha否则为空字符串
// CNB_PULL_REQUEST_MERGE_SHA 对于由 pull_request.merged 触发的构建,值为合并后的 sha对于 pull_request 等触发的构建,值为预合并后的 sha否则为空字符串
// CNB_PULL_REQUEST_SLUG 对于由 合并类事件 触发的构建,值为源仓库的仓库 slug如 group_slug/repo_name否则为空字符串
// CNB_PULL_REQUEST_ACTION 对于由 合并类事件 触发的构建可能的值有created(新建PR)、code_update(源分支push)、status_update(评审通过或CI状态变更),否则为空字符串
// CNB_PULL_REQUEST_ID 对于由 合并类事件 触发的构建,值为当前或者关联 PR 的全局唯一 id否则为空字符串
export const usePullRequestEnv = () => {
const pullRequest = useKey("CNB_PULL_REQUEST");
const pullRequestLike = useKey("CNB_PULL_REQUEST_LIKE");
const pullRequestProposer = useKey("CNB_PULL_REQUEST_PROPOSER");
const pullRequestTitle = useKey("CNB_PULL_REQUEST_TITLE");
const pullRequestBranch = useKey("CNB_PULL_REQUEST_BRANCH");
const pullRequestSha = useKey("CNB_PULL_REQUEST_SHA");
const pullRequestTargetSha = useKey("CNB_PULL_REQUEST_TARGET_SHA");
const pullRequestMergeSha = useKey("CNB_PULL_REQUEST_MERGE_SHA");
const pullRequestSlug = useKey("CNB_PULL_REQUEST_SLUG");
const pullRequestAction = useKey("CNB_PULL_REQUEST_ACTION");
const pullRequestId = useKey("CNB_PULL_REQUEST_ID");
return {
/**
* @key CNB_PULL_REQUEST
* @description:对于由 pull_request、pull_request.update、pull_request.target 触发的构建,值为 true否则为 false
*/
pullRequest,
pullRequestLabel: "对于由 pull_request、pull_request.update、pull_request.target 触发的构建,值为 true否则为 false",
/**
* @key CNB_PULL_REQUEST_LIKE
* @description:对于由 合并类事件 触发的构建,值为 true否则为 false
*/
pullRequestLike,
pullRequestLikeLabel: "对于由 合并类事件 触发的构建,值为 true否则为 false",
/**
* @key CNB_PULL_REQUEST_PROPOSER
* @description:对于由 合并类事件 触发的构建,值为提出 PR 者名称,否则为空字符串
*/
pullRequestProposer,
pullRequestProposerLabel: "对于由 合并类事件 触发的构建,值为提出 PR 者名称,否则为空字符串",
/**
* @key CNB_PULL_REQUEST_TITLE
* @description:对于由 合并类事件 触发的构建,值为提 PR 时候填写的标题,否则为空字符串
*/
pullRequestTitle,
pullRequestTitleLabel: "对于由 合并类事件 触发的构建,值为提 PR 时候填写的标题,否则为空字符串",
/**
* @key CNB_PULL_REQUEST_BRANCH
* @description:对于由 合并类事件 触发的构建,值为发起 PR 的源分支名称,否则为空字符串
*/
pullRequestBranch,
pullRequestBranchLabel: "对于由 合并类事件 触发的构建,值为发起 PR 的源分支名称,否则为空字符串",
/**
* @key CNB_PULL_REQUEST_SHA
* @description:对于由 合并类事件 触发的构建,值为当前 PR 源分支最新的提交 sha否则为空字符串
*/
pullRequestSha,
pullRequestShaLabel: "对于由 合并类事件 触发的构建,值为当前 PR 源分支最新的提交 sha否则为空字符串",
/**
* @key CNB_PULL_REQUEST_TARGET_SHA
* @description:对于由 合并类事件 触发的构建,值为当前 PR 目标分支最新的提交 sha否则为空字符串
*/
pullRequestTargetSha,
pullRequestTargetShaLabel: "对于由 合并类事件 触发的构建,值为当前 PR 目标分支最新的提交 sha否则为空字符串",
/**
* @key CNB_PULL_REQUEST_MERGE_SHA
* @description:对于由 pull_request.merged 触发的构建,值为合并后的 sha对于 pull_request 等触发的构建,值为预合并后的 sha否则为空字符串
*/
pullRequestMergeSha,
pullRequestMergeShaLabel: "对于由 pull_request.merged 触发的构建,值为合并后的 sha对于 pull_request 等触发的构建,值为预合并后的 sha否则为空字符串",
/**
* @key CNB_PULL_REQUEST_SLUG
* @description:对于由 合并类事件 触发的构建,值为源仓库的仓库 slug如 group_slug/repo_name否则为空字符串
*/
pullRequestSlug,
pullRequestSlugLabel: "对于由 合并类事件 触发的构建,值为源仓库的仓库 slug如 group_slug/repo_name否则为空字符串",
/**
* @key CNB_PULL_REQUEST_ACTION
* @description:对于由 合并类事件 触发的构建可能的值有created(新建PR)、code_update(源分支push)、status_update(评审通过或CI状态变更),否则为空字符串
*/
pullRequestAction,
pullRequestActionLabel: "对于由 合并类事件 触发的构建可能的值有created(新建PR)、code_update(源分支push)、status_update(评审通过或CI状态变更),否则为空字符串",
/**
* @key CNB_PULL_REQUEST_ID
* @description:对于由 合并类事件 触发的构建,值为当前或者关联 PR 的全局唯一 id否则为空字符串
*/
pullRequestId,
pullRequestIdLabel: "对于由 合并类事件 触发的构建,值为当前或者关联 PR 的全局唯一 id否则为空字符串"
};
}

56
src/issue/npc/repo-env.ts Normal file
View File

@@ -0,0 +1,56 @@
import { useKey } from "@kevisual/context";
// CNB_REPO_SLUG kevision/dev-cnb 目标仓库路径,格式为 group_slug / repo_namegroup_slug / sub_gourp_slug /.../repo_name
// CNB_REPO_SLUG_LOWERCASE kevision/dev-cnb 目标仓库路径小写格式
// CNB_REPO_NAME dev-cnb 目标仓库名称
// CNB_REPO_NAME_LOWERCASE dev-cnb 目标仓库名称小写格式
// CNB_REPO_ID 2026263219584110592 目标仓库的 id
// CNB_REPO_URL_HTTPS 目标仓库 https 地址
export const useRepoInfoEnv = () => {
const repoSlug = useKey("CNB_REPO_SLUG");
const repoSlugLowercase = useKey("CNB_REPO_SLUG_LOWERCASE");
const repoName = useKey("CNB_REPO_NAME");
const repoNameLowercase = useKey("CNB_REPO_NAME_LOWERCASE");
const repoId = useKey("CNB_REPO_ID");
const repoUrlHttps = useKey("CNB_REPO_URL_HTTPS");
return {
/**
* @key CNB_REPO_SLUG
* @description:目标仓库路径,格式为 group_slug/repo_namegroup_slug/sub_group_slug/.../repo_name
*/
repoSlug,
repoSlugLabel: "目标仓库路径,格式为 group_slug/repo_namegroup_slug/sub_group_slug/.../repo_name",
/**
* @key CNB_REPO_SLUG_LOWERCASE
* @description:目标仓库路径小写格式
*/
repoSlugLowercase,
repoSlugLowercaseLabel: "目标仓库路径小写格式",
/**
* @key CNB_REPO_NAME
* @description:目标仓库名称
*/
repoName,
repoNameLabel: "目标仓库名称",
/**
* @key CNB_REPO_NAME_LOWERCASE
* @description:目标仓库名称小写格式
*/
repoNameLowercase,
repoNameLowercaseLabel: "目标仓库名称小写格式",
/**
* @key CNB_REPO_ID
* @description:目标仓库的 id
*/
repoId,
repoIdLabel: "目标仓库的 id",
/**
* @key CNB_REPO_URL_HTTPS
* @description:目标仓库 https 地址
*/
repoUrlHttps,
repoUrlHttpsLabel: "目标仓库 https 地址"
};
}

View File

@@ -1,5 +1,5 @@
import { CNBCore, CNBCoreOptions, RequestOptions, Result } from "../cnb-core.ts";
import dayjs from "dayjs";
export class Repo extends CNBCore {
constructor(options: CNBCoreOptions) {
super(options);
@@ -30,6 +30,12 @@ export class Repo extends CNBCore {
const url = `/${repo}`;
return this.delete({ url });
}
/**
* 使用cookie创建提交如果没有指定parent_commit_sha则会自动获取最新的提交作为父提交
* @param repo
* @param data
* @returns
*/
async createCommit(repo: string, data: CreateCommitData): Promise<any> {
const commitList = await this.getCommitList(repo, {
page: 1,
@@ -41,6 +47,12 @@ export class Repo extends CNBCore {
const preCommitSha = commitList.length > 0 ? commitList[0].sha : undefined;
if (!data.parent_commit_sha && preCommitSha) {
data.parent_commit_sha = preCommitSha;
} else if (data.parent_commit_sha) {
// 如果指定了parent_commi_sha;
if (!data.new_branch) {
const date = dayjs().format('MMDDHHmm');
data.new_branch = `refs/heads/${date}`;
}
}
const url = `${this.hackURL}/${repo}/-/git/commits`;
const postData: CreateCommitData = {
@@ -52,6 +64,7 @@ export class Repo extends CNBCore {
new_branch: data.new_branch || 'refs/heads/main',
};
if (!postData.parent_commit_sha) {
// 如果没有父提交sha则说明是第一次提交可以删除parent_commit_sha和base_branch字段
delete postData.parent_commit_sha;
delete postData.base_branch;
}

12
test/a-config.ts Normal file
View File

@@ -0,0 +1,12 @@
import { getConfig } from '../agent/modules/cnb-manager';
import { QueryLoginNode } from '@kevisual/api/login-node';
const queryLoginNode = new QueryLoginNode({});
await queryLoginNode.init()
const testConfig = async () => {
const token = await queryLoginNode.getToken();
console.log('Token:', token);
const res = await getConfig({ token });
console.log('Config:', res);
}
testConfig();

43
test/issue-comment.ts Normal file
View File

@@ -0,0 +1,43 @@
import { Issue } from "../src/issue/index.ts";
import { token, showMore, cookie } from "./common.ts";
const issue = new Issue({
token: token,
cookie: cookie
});
const repo = "kevisual/dev-env";
const issueNumber = 5;
// 1. 查询评论列表
console.log("=== 1. 查询评论列表 ===");
const commentListRes = await issue.getCommentList(repo, issueNumber, {
page: 1,
page_size: 30
});
console.log(showMore(commentListRes));
// 2. 创建评论
console.log("\n=== 2. 创建评论 ===");
const createRes = await issue.createComment(repo, issueNumber, "测试评论内容 " + new Date().toISOString());
console.log(showMore(createRes));
// 如果创建成功,获取评论 ID
let commentId = null;
if (createRes.code === 200 && createRes.data?.id) {
commentId = createRes.data.id;
console.log("创建的评论 ID:", commentId);
// 3. 获取单个评论
console.log("\n=== 3. 获取单个评论 ===");
const getRes = await issue.getComment(repo, issueNumber, commentId);
console.log(showMore(getRes));
// 4. 修改评论
console.log("\n=== 4. 修改评论 ===");
const updateRes = await issue.updateComment(repo, issueNumber, commentId, "这是修改后的评论内容 " + new Date().toISOString());
console.log(showMore(updateRes));
}
const env = issue.useCommentEnv();
process.exit(0);

27
test/npc-test.ts Normal file
View File

@@ -0,0 +1,27 @@
import { fork } from 'node:child_process';
import path from 'node:path';
const runCmd = () => {
const filePath = path.resolve(process.cwd(), 'agent/npc.ts');
const child = fork(filePath, {
env: {
...process.env,
// CNB_COMMENT_BODY: '@kevisual/cnb(router) 我的kevisual/cnb的issues列表',
CNB_COMMENT_BODY: '关闭仓库的issue。kevisual/cnb/-/issues/5',
CNB_ISSUE_ID: '6',
CNB_ISSUE_TITLE: '托尔斯泰',
CNB_REPO_SLUG: 'kevisual/cnb',
},
stdio: 'inherit',
});
child.on('error', (err) => {
console.error('Error in child process:', err);
});
child.on('exit', (code) => {
console.log(`Child process exited with code ${code}`);
});
}
runCmd();

11
test/version.test.ts Normal file
View File

@@ -0,0 +1,11 @@
import { getCNBVersion } from '../src/index.ts';
import { describe, it, expect } from 'bun:test';
describe('getCNBVersion', () => {
it('should return version info', async () => {
const versionInfo = await getCNBVersion();
expect(versionInfo).toHaveProperty('version');
expect(versionInfo).toHaveProperty('commitID');
expect(versionInfo).toHaveProperty('hash');
});
});