Compare commits
16 Commits
da7b06e519
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 412c057756 | |||
| 7a01339ef2 | |||
| 6e5a642ab2 | |||
| 0d17d56628 | |||
| 972d68b87e | |||
| 28484baab3 | |||
| d7a4bcf58f | |||
| 1d4a27d1b2 | |||
| 5db3b4a51b | |||
| 86b24cc9ef | |||
| e15cf4f7be | |||
|
|
20fcf2dca8 | ||
|
|
8e1880a343 | ||
|
|
7b31367c1d | ||
|
|
b15b11fa02 | ||
|
|
50332fe2f4 |
2
.cnb.yml
2
.cnb.yml
@@ -21,7 +21,7 @@ $:
|
|||||||
# stages:
|
# stages:
|
||||||
# - name: pnpm install
|
# - name: pnpm install
|
||||||
# script: pnpm install
|
# script: pnpm install
|
||||||
stages: !reference [.dev_tempalte, stages]
|
stages: !reference [.dev_template, stages]
|
||||||
|
|
||||||
.common_sync_to_gitea: &common_sync_to_gitea
|
.common_sync_to_gitea: &common_sync_to_gitea
|
||||||
- <<: *common_env
|
- <<: *common_env
|
||||||
|
|||||||
@@ -95,7 +95,7 @@
|
|||||||
|
|
||||||
|
|
||||||
# 开发环境模版
|
# 开发环境模版
|
||||||
.dev_tempalte: &dev_tempalte
|
.dev_template: &dev_template
|
||||||
services:
|
services:
|
||||||
- vscode
|
- vscode
|
||||||
docker:
|
docker:
|
||||||
|
|||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -2,3 +2,7 @@
|
|||||||
.env.local
|
.env.local
|
||||||
node_modules
|
node_modules
|
||||||
.pnpm-store
|
.pnpm-store
|
||||||
|
|
||||||
|
dist
|
||||||
|
|
||||||
|
storage
|
||||||
3
.npmrc
Normal file
3
.npmrc
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
//npm.xiongxiao.me/:_authToken=${ME_NPM_TOKEN}
|
||||||
|
//npm.cnb.cool/kevisual/registry/-/packages/:_authToken=${CNB_API_KEY}
|
||||||
|
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||||
@@ -1 +1 @@
|
|||||||
export * from "../../agent/opencode-plugin";
|
export * from "../../agent/opencode";
|
||||||
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"code-runner.executorMap": {
|
|
||||||
"ts": "opencode run $selectedText"
|
|
||||||
},
|
|
||||||
"code-runner.runInTerminal": true
|
|
||||||
}
|
|
||||||
11
agent/app.ts
11
agent/app.ts
@@ -2,17 +2,16 @@ import { QueryRouterServer as App } from '@kevisual/router'
|
|||||||
import { useContextKey } from '@kevisual/context'
|
import { useContextKey } from '@kevisual/context'
|
||||||
import { useConfig, useKey } from '@kevisual/use-config'
|
import { useConfig, useKey } from '@kevisual/use-config'
|
||||||
import { CNB } from '../src/index.ts';
|
import { CNB } from '../src/index.ts';
|
||||||
import { nanoid } from 'nanoid';
|
|
||||||
|
|
||||||
export const config = useConfig()
|
export const config = useConfig()
|
||||||
export const cnb = useContextKey<CNB>('cnb', () => {
|
export const cnb = useContextKey<CNB>('cnb', () => {
|
||||||
const token = useKey('CNB_API_KEY') as string
|
// 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
|
const cookie = useKey('CNB_COOKIE') as string
|
||||||
return new CNB({ token: token, cookie: cookie });
|
return new CNB({ token: token, cookie: cookie });
|
||||||
})
|
})
|
||||||
export const appId = nanoid();
|
|
||||||
export const app = useContextKey<App>('app', () => {
|
export const app = useContextKey<App>('app', () => {
|
||||||
return new App({
|
return new App({})
|
||||||
appId
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
import { tool } from "@opencode-ai/plugin/tool"
|
|
||||||
import { type Plugin } from "@opencode-ai/plugin"
|
|
||||||
import { app, cnb, appId } from './index.ts';
|
|
||||||
import { } from 'es-toolkit'
|
|
||||||
import { Skill } from "@kevisual/router";
|
|
||||||
|
|
||||||
const routes = app.routes.filter(r => {
|
|
||||||
const metadata = r.metadata as Skill
|
|
||||||
if (metadata && metadata.tags && metadata.tags.includes('opencode')) {
|
|
||||||
return !!metadata.skill
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
|
|
||||||
// opencode run "请使用 cnb-login-verify 工具验证登录信信息,检查cookie"
|
|
||||||
export const CnbPlugin: Plugin = async ({ project, client, $, directory, worktree }) => {
|
|
||||||
return {
|
|
||||||
'tool': {
|
|
||||||
...routes.reduce((acc, route) => {
|
|
||||||
const metadata = route.metadata as Skill
|
|
||||||
acc[metadata.skill!] = {
|
|
||||||
name: metadata.title || metadata.skill,
|
|
||||||
description: metadata.summary || '',
|
|
||||||
args: metadata.args || {},
|
|
||||||
async execute(args: Record<string, any>) {
|
|
||||||
console.log(`Executing skill ${metadata.skill} with args:`, args);
|
|
||||||
await client.app.log({
|
|
||||||
body: {
|
|
||||||
service: 'cnb',
|
|
||||||
level: 'info',
|
|
||||||
message: `Executing skill ${metadata.skill} with args: ${JSON.stringify(args)}`
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const res = await app.run({
|
|
||||||
path: route.path,
|
|
||||||
key: route.key,
|
|
||||||
payload: args
|
|
||||||
}, { appId });
|
|
||||||
if (res.code === 200) {
|
|
||||||
if (res.data?.content) {
|
|
||||||
return res.data.content;
|
|
||||||
}
|
|
||||||
const str = JSON.stringify(res.data || res, null, 2);
|
|
||||||
if (str.length > 5000) {
|
|
||||||
return str.slice(0, 5000) + '... (truncated)';
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
return `Error: ${res?.message || '无法获取结果'}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return acc;
|
|
||||||
}, {} as Record<string, any>)
|
|
||||||
},
|
|
||||||
'tool.execute.before': async (opts) => {
|
|
||||||
// console.log('CnbPlugin: tool.execute.before', opts.tool);
|
|
||||||
// delete toolSkills['cnb-login-verify']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const demo = {
|
|
||||||
'tool': {
|
|
||||||
"cnb-login-verify": {
|
|
||||||
name: "CNB 登录验证信息",
|
|
||||||
description: "验证 CNB 登录信息是否有效",
|
|
||||||
args: {
|
|
||||||
checkToken: tool.schema.boolean().describe("是否检查 Token 的有效性").default(true),
|
|
||||||
checkCookie: tool.schema.boolean().describe("是否检查 Cookie 的有效性").default(false),
|
|
||||||
},
|
|
||||||
async execute(args) {
|
|
||||||
const res = await app.run({
|
|
||||||
path: 'cnb',
|
|
||||||
key: 'user-check',
|
|
||||||
payload: {
|
|
||||||
...args
|
|
||||||
}
|
|
||||||
}, { appId });
|
|
||||||
if (res.code === 200) {
|
|
||||||
return res.data?.output;
|
|
||||||
}
|
|
||||||
return '无法获取登录状态,请检查配置。';
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
6
agent/opencode.ts
Normal file
6
agent/opencode.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { app } from './index.ts';
|
||||||
|
import { createRouterAgentPluginFn } from '@kevisual/router/opencode'
|
||||||
|
|
||||||
|
export const CnbPlugin = createRouterAgentPluginFn({
|
||||||
|
router: app,
|
||||||
|
})
|
||||||
@@ -2,31 +2,33 @@ import { createSkill } from '@kevisual/router'
|
|||||||
import { app } from '../../app.ts'
|
import { app } from '../../app.ts'
|
||||||
import { tool } from '@opencode-ai/plugin/tool'
|
import { tool } from '@opencode-ai/plugin/tool'
|
||||||
|
|
||||||
// "调用 path: cnb key: list-repos"
|
if (!app.hasRoute('call')) {
|
||||||
app.route({
|
// "调用 path: cnb key: list-repos"
|
||||||
path: 'call',
|
app.route({
|
||||||
key: '',
|
path: 'call',
|
||||||
description: '调用',
|
key: '',
|
||||||
middleware: ['auth'],
|
description: '调用',
|
||||||
metadata: {
|
middleware: ['admin-auth'],
|
||||||
tags: ['opencode'],
|
metadata: {
|
||||||
...createSkill({
|
tags: ['opencode'],
|
||||||
skill: 'call-app',
|
...createSkill({
|
||||||
title: '调用app应用',
|
skill: 'call-app',
|
||||||
summary: '调用router的应用, 参数path, key, payload',
|
title: '调用app应用',
|
||||||
args: {
|
summary: '调用router的应用, 参数path, key, payload',
|
||||||
path: tool.schema.string().describe('应用路径,例如 cnb'),
|
args: {
|
||||||
key: tool.schema.string().optional().describe('应用key,例如 list-repos'),
|
path: tool.schema.string().describe('应用路径,例如 cnb'),
|
||||||
payload: tool.schema.object({}).optional().describe('调用参数'),
|
key: tool.schema.string().optional().describe('应用key,例如 list-repos'),
|
||||||
}
|
payload: tool.schema.object({}).optional().describe('调用参数'),
|
||||||
})
|
}
|
||||||
},
|
})
|
||||||
}).define(async (ctx) => {
|
},
|
||||||
const { path, key } = ctx.query;
|
}).define(async (ctx) => {
|
||||||
console.log('call app', ctx.query);
|
const { path, key } = ctx.query;
|
||||||
if (!path) {
|
console.log('call app', ctx.query);
|
||||||
ctx.throw('路径path不能为空');
|
if (!path) {
|
||||||
}
|
ctx.throw('路径path不能为空');
|
||||||
const res = await ctx.run({ path, key, payload: ctx.query.payload || {} });
|
}
|
||||||
ctx.forward(res);
|
const res = await ctx.run({ path, key, payload: ctx.query.payload || {} });
|
||||||
}).addTo(app)
|
ctx.forward(res);
|
||||||
|
}).addTo(app)
|
||||||
|
}
|
||||||
@@ -1 +0,0 @@
|
|||||||
调用 path: cnb key: get-repo-list payload: { page: 1, per_page: 10 }
|
|
||||||
@@ -7,7 +7,7 @@ app.route({
|
|||||||
path: 'cnb',
|
path: 'cnb',
|
||||||
key: 'user-check',
|
key: 'user-check',
|
||||||
description: '检查用户登录状态,参数checkToken,default true; checkCookie, default false',
|
description: '检查用户登录状态,参数checkToken,default true; checkCookie, default false',
|
||||||
middleware: ['auth'],
|
middleware: ['admin-auth'],
|
||||||
metadata: {
|
metadata: {
|
||||||
tags: ['opencode'],
|
tags: ['opencode'],
|
||||||
...createSkill({
|
...createSkill({
|
||||||
48
agent/routes/cnb-env/env.ts
Normal file
48
agent/routes/cnb-env/env.ts
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import { createSkill, tool } from '@kevisual/router';
|
||||||
|
import { app, cnb } from '../../app.ts';
|
||||||
|
|
||||||
|
// 设置 CNB_COOKIE环境变量和获取环境变量,用于界面操作定制模块功能
|
||||||
|
app.route({
|
||||||
|
path: 'cnb',
|
||||||
|
key: 'set-cnb-cookie',
|
||||||
|
description: '设置当前cnb工作空间的cookie环境变量',
|
||||||
|
middleware: ['admin-auth'],
|
||||||
|
metadata: {
|
||||||
|
tags: ['opencode'],
|
||||||
|
...createSkill({
|
||||||
|
skill: 'set-cnb-cookie',
|
||||||
|
title: '设置当前cnb工作空间的cookie环境变量',
|
||||||
|
summary: '设置当前cnb工作空间的cookie环境变量,用于界面操作定制模块功能,例子:CNBSESSION=xxxx;csrfkey=2222xxxx;',
|
||||||
|
args: {
|
||||||
|
cookie: tool.schema.string().describe('cnb的cookie值'),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).define(async (ctx) => {
|
||||||
|
const cookie = ctx.query?.cookie;
|
||||||
|
if (!cookie) {
|
||||||
|
ctx.body = { content: '请提供有效的cookie值' };
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cnb.cookie = cookie;
|
||||||
|
ctx.body = { content: '已成功设置cnb的cookie环境变量' };
|
||||||
|
}).addTo(app);
|
||||||
|
|
||||||
|
// 获取 CNB_COOKIE环境变量
|
||||||
|
app.route({
|
||||||
|
path: 'cnb',
|
||||||
|
key: 'get-cnb-cookie',
|
||||||
|
description: '获取当前cnb工作空间的cookie环境变量',
|
||||||
|
middleware: ['admin-auth'],
|
||||||
|
metadata: {
|
||||||
|
tags: ['opencode'],
|
||||||
|
...createSkill({
|
||||||
|
skill: 'get-cnb-cookie',
|
||||||
|
title: '获取当前cnb工作空间的cookie环境变量',
|
||||||
|
summary: '获取当前cnb工作空间的cookie环境变量,用于界面操作定制模块功能',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).define(async (ctx) => {
|
||||||
|
const cookie = cnb.cookie || '未设置cookie环境变量';
|
||||||
|
ctx.body = { content: `当前cnb工作空间的cookie环境变量为:${cookie}` };
|
||||||
|
}).addTo(app);
|
||||||
@@ -1 +1,3 @@
|
|||||||
// 根据环境变量获取当前的 cnb 启动环境
|
// 根据环境变量获取当前的 cnb 启动环境
|
||||||
|
import './vscode.ts';
|
||||||
|
import './env.ts';
|
||||||
96
agent/routes/cnb-env/vscode.ts
Normal file
96
agent/routes/cnb-env/vscode.ts
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
import { createSkill, tool } from '@kevisual/router';
|
||||||
|
import { app, cnb } from '../../app.ts';
|
||||||
|
|
||||||
|
import { CNB_ENV } from "@/common/cnb-env.ts";
|
||||||
|
|
||||||
|
// 执行技能 get-cnb-port-uri,端口为4096
|
||||||
|
// 执行技能 get-cnb-port-uri,端口为51515
|
||||||
|
|
||||||
|
// TODO: 获取仓库的
|
||||||
|
app.route({
|
||||||
|
path: 'cnb',
|
||||||
|
key: 'get-cnb-port-uri',
|
||||||
|
description: '获取当前cnb工作空间的port代理uri',
|
||||||
|
middleware: ['admin-auth'],
|
||||||
|
metadata: {
|
||||||
|
tags: ['opencode'],
|
||||||
|
...createSkill({
|
||||||
|
skill: 'get-cnb-port-uri',
|
||||||
|
title: '获取当前cnb工作空间的port代理uri',
|
||||||
|
summary: '获取当前cnb工作空间的port代理uri,用于端口转发',
|
||||||
|
args: {
|
||||||
|
port: tool.schema.number().optional().describe('端口号,默认为4096'),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).define(async (ctx) => {
|
||||||
|
const port = ctx.query?.port || 4096;
|
||||||
|
const uri = CNB_ENV?.CNB_VSCODE_PROXY_URI as string || '';
|
||||||
|
const finalUri = uri.replace('{{port}}', port.toString());
|
||||||
|
let content = `
|
||||||
|
cnb工作空间的访问uri为:${finalUri}
|
||||||
|
`
|
||||||
|
ctx.body = { content };
|
||||||
|
}).addTo(app);
|
||||||
|
|
||||||
|
// 获取当前cnb工作空间的vscode代理uri,执行技能 get-cnb-vscode-uri
|
||||||
|
// 包括 web 访问uri,vscode 访问uri,codebuddy 访问uri,cursor 访问uri,ssh 连接字符串
|
||||||
|
|
||||||
|
app.route({
|
||||||
|
path: 'cnb',
|
||||||
|
key: 'get-cnb-vscode-uri',
|
||||||
|
description: '获取当前cnb工作空间的vscode代理uri, 包括多种访问方式, 如web、vscode、codebuddy、cursor、ssh',
|
||||||
|
middleware: ['admin-auth'],
|
||||||
|
metadata: {
|
||||||
|
tags: ['opencode'],
|
||||||
|
...createSkill({
|
||||||
|
skill: 'get-cnb-vscode-uri',
|
||||||
|
title: '获取当前cnb工作空间的编辑器访问地址',
|
||||||
|
summary: '获取当前cnb工作空间的vscode代理uri,用于在浏览器中访问vscode,包含多种访问方式,如web、vscode、codebuddy、cursor、ssh',
|
||||||
|
args: {
|
||||||
|
web: tool.schema.boolean().optional().describe('是否获取vscode web的访问uri,默认为false'),
|
||||||
|
vscode: tool.schema.boolean().optional().describe('是否获取vscode的代理uri,默认为true'),
|
||||||
|
codebuddy: tool.schema.boolean().optional().describe('是否获取codebuddy的代理uri,默认为false'),
|
||||||
|
cursor: tool.schema.boolean().optional().describe('是否获取cursor的代理uri,默认为false'),
|
||||||
|
// trae: tool.schema.boolean().optional().describe('是否获取trae的代理uri,默认为false'),
|
||||||
|
ssh: tool.schema.boolean().optional().describe('是否获取vscode remote ssh的连接字符串,默认为false'),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).define(async (ctx) => {
|
||||||
|
const web = ctx.query?.web ?? false;
|
||||||
|
const vscode = ctx.query?.vscode ?? true; // 默认true
|
||||||
|
const codebuddy = ctx.query?.codebuddy ?? false;
|
||||||
|
const cursor = ctx.query?.cursor ?? false;
|
||||||
|
// const trae = ctx.query?.trae ?? false;
|
||||||
|
const ssh = ctx.query?.ssh ?? false;
|
||||||
|
|
||||||
|
const webUri = CNB_ENV?.CNB_VSCODE_WEB_URL as string || '';
|
||||||
|
const vscodeSchma = CNB_ENV?.CNB_VSCODE_REMOTE_SSH_SCHEMA as string || '';
|
||||||
|
let content = `
|
||||||
|
当前的cnb 仓库为:${CNB_ENV?.CNB_REPO_SLUG}
|
||||||
|
|
||||||
|
`
|
||||||
|
if (web) {
|
||||||
|
content += `VS Code Web 访问 URI:${webUri}\n\n`;
|
||||||
|
}
|
||||||
|
if (vscode) {
|
||||||
|
content += `VS Code 访问 URI:${vscodeSchma}\n\n`;
|
||||||
|
}
|
||||||
|
if (codebuddy) {
|
||||||
|
const codebuddyUri = vscodeSchma.replace('vscode://vscode-remote/ssh-remote+', 'codebuddycn://vscode-remote/codebuddy-remote');
|
||||||
|
content += `CodeBuddy 访问 URI:${codebuddyUri}\n\n`;
|
||||||
|
}
|
||||||
|
if (cursor) {
|
||||||
|
const cursorUri = vscodeSchma.replace('vscode://', 'cursor://');
|
||||||
|
content += `Cursor 访问 URI:${cursorUri}\n\n`;
|
||||||
|
}
|
||||||
|
// if (trae) {
|
||||||
|
// const traeUri = vscodeSchma.replace('vscode://vscode-remote/ssh-remote+', 'traecn://ssh-remote+');
|
||||||
|
// content += `Trae 访问 URI:${traeUri}\n\n`;
|
||||||
|
// }
|
||||||
|
if (ssh) {
|
||||||
|
content += `VS Code Remote SSH 连接字符串:ssh ${CNB_ENV.CNB_PIPELINE_ID}.${CNB_ENV.CNB_VSCODE_SSH_TOKEN}@cnb.space`;
|
||||||
|
}
|
||||||
|
ctx.body = { content };
|
||||||
|
}).addTo(app);
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
import { app, appId } from '../app.ts';
|
import { app } from '../app.ts';
|
||||||
import './user/check.ts'
|
import './cnb-env/check.ts'
|
||||||
import './repo/index.ts'
|
import './repo/index.ts'
|
||||||
import './workspace/index.ts'
|
import './workspace/index.ts'
|
||||||
import './call/index.ts'
|
import './call/index.ts'
|
||||||
|
import './cnb-env/index.ts'
|
||||||
|
import './knowledge/index.ts'
|
||||||
|
import './issues/index.ts'
|
||||||
|
|
||||||
import { isEqual } from 'es-toolkit'
|
|
||||||
/**
|
/**
|
||||||
* 验证上下文中的 App ID 是否与指定的 App ID 匹配
|
* 验证上下文中的 App ID 是否与指定的 App ID 匹配
|
||||||
* @param {any} ctx - 上下文对象,可能包含 appId 属性
|
* @param {any} ctx - 上下文对象,可能包含 appId 属性
|
||||||
@@ -29,7 +31,7 @@ if (!app.hasRoute('auth')) {
|
|||||||
path: 'auth',
|
path: 'auth',
|
||||||
}).define(async (ctx) => {
|
}).define(async (ctx) => {
|
||||||
// ctx.body = 'Auth Route';
|
// ctx.body = 'Auth Route';
|
||||||
if (checkAppId(ctx, appId)) {
|
if (checkAppId(ctx, app.appId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}).addTo(app);
|
}).addTo(app);
|
||||||
@@ -40,7 +42,7 @@ if (!app.hasRoute('auth')) {
|
|||||||
middleware: ['auth'],
|
middleware: ['auth'],
|
||||||
}).define(async (ctx) => {
|
}).define(async (ctx) => {
|
||||||
// ctx.body = 'Admin Auth Route';
|
// ctx.body = 'Admin Auth Route';
|
||||||
if (checkAppId(ctx, appId)) {
|
if (checkAppId(ctx, app.appId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}).addTo(app);
|
}).addTo(app);
|
||||||
|
|||||||
2
agent/routes/issues/index.ts
Normal file
2
agent/routes/issues/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
import './list.ts'
|
||||||
|
import './issue.ts'
|
||||||
82
agent/routes/issues/issue.ts
Normal file
82
agent/routes/issues/issue.ts
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import { createSkill, tool } from '@kevisual/router';
|
||||||
|
import { app, cnb } from '../../app.ts';
|
||||||
|
import { IssueItem } from '@/index.ts';
|
||||||
|
|
||||||
|
// 创建cnb issue, 仓库为 kevisual/kevisual 标题为 "自动化测试创建issue", 内容为 "这是通过API创建的issue,用于测试目的", body: "这是通过API创建的issue,用于测试目的"
|
||||||
|
app.route({
|
||||||
|
path: 'cnb',
|
||||||
|
key: 'create-issue',
|
||||||
|
description: '创建 Issue, 参数 repo, title, body, assignees, labels, priority',
|
||||||
|
middleware: ['admin-auth'],
|
||||||
|
metadata: {
|
||||||
|
tags: ['opencode'],
|
||||||
|
...createSkill({
|
||||||
|
skill: 'create-issue',
|
||||||
|
title: '创建 Issue',
|
||||||
|
args: {
|
||||||
|
repo: tool.schema.string().describe('代码仓库名称, 如 my-user/my-repo'),
|
||||||
|
title: tool.schema.string().describe('Issue 标题'),
|
||||||
|
body: tool.schema.string().optional().describe('Issue 描述内容'),
|
||||||
|
assignees: tool.schema.array(tool.schema.string()).optional().describe('指派人列表'),
|
||||||
|
labels: tool.schema.array(tool.schema.string()).optional().describe('标签列表'),
|
||||||
|
priority: tool.schema.string().optional().describe('优先级'),
|
||||||
|
},
|
||||||
|
summary: '创建一个新的 Issue',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).define(async (ctx) => {
|
||||||
|
const repo = ctx.query?.repo;
|
||||||
|
const title = ctx.query?.title;
|
||||||
|
const body = ctx.query?.body;
|
||||||
|
const assignees = ctx.query?.assignees;
|
||||||
|
const labels = ctx.query?.labels;
|
||||||
|
const priority = ctx.query?.priority;
|
||||||
|
|
||||||
|
if (!repo || !title) {
|
||||||
|
ctx.throw(400, '缺少参数 repo 或 title');
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await cnb.issue.createIssue(repo, {
|
||||||
|
title,
|
||||||
|
body,
|
||||||
|
assignees,
|
||||||
|
labels,
|
||||||
|
priority,
|
||||||
|
});
|
||||||
|
ctx.forward(res);
|
||||||
|
}).addTo(app);
|
||||||
|
|
||||||
|
// 完成 issue 8, 仓库是 kevisual/kevisaul
|
||||||
|
app.route({
|
||||||
|
path: 'cnb',
|
||||||
|
key: 'complete-issue',
|
||||||
|
description: '完成 Issue, 参数 repo, issueNumber',
|
||||||
|
middleware: ['admin-auth'],
|
||||||
|
metadata: {
|
||||||
|
tags: ['opencode'],
|
||||||
|
...createSkill({
|
||||||
|
skill: 'complete-issue',
|
||||||
|
title: '完成 CNB的任务Issue',
|
||||||
|
args: {
|
||||||
|
repo: tool.schema.string().describe('代码仓库名称, 如 my-user/my-repo'),
|
||||||
|
issueNumber: tool.schema.union([tool.schema.string(), tool.schema.number()]).describe('Issue 编号'),
|
||||||
|
state: tool.schema.string().optional().describe('Issue 状态,默认为 closed'),
|
||||||
|
},
|
||||||
|
summary: '完成一个 Issue(将 state 改为 closed)',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).define(async (ctx) => {
|
||||||
|
const repo = ctx.query?.repo;
|
||||||
|
const issueNumber = ctx.query?.issueNumber;
|
||||||
|
const state = ctx.query?.state ?? 'closed';
|
||||||
|
|
||||||
|
if (!repo || !issueNumber) {
|
||||||
|
ctx.throw(400, '缺少参数 repo 或 issueNumber');
|
||||||
|
}
|
||||||
|
const iss: Partial<IssueItem> = { state: state };
|
||||||
|
if (iss.state === 'closed') {
|
||||||
|
iss.state_reason = 'completed';
|
||||||
|
}
|
||||||
|
const res = await cnb.issue.updateIssue(repo, issueNumber, iss);
|
||||||
|
ctx.forward(res);
|
||||||
|
}).addTo(app);
|
||||||
50
agent/routes/issues/list.ts
Normal file
50
agent/routes/issues/list.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { createSkill, tool } from '@kevisual/router';
|
||||||
|
import { app, cnb } from '../../app.ts';
|
||||||
|
|
||||||
|
// 查询 Issue 列表 repo是 kevisual/kevisual
|
||||||
|
app.route({
|
||||||
|
path: 'cnb',
|
||||||
|
key: 'list-issues',
|
||||||
|
description: '查询 Issue 列表, 参数 repo, state, keyword, labels, page, page_size 等',
|
||||||
|
middleware: ['admin-auth'],
|
||||||
|
metadata: {
|
||||||
|
tags: ['opencode'],
|
||||||
|
...createSkill({
|
||||||
|
skill: 'list-issues',
|
||||||
|
title: '查询 Issue 列表',
|
||||||
|
args: {
|
||||||
|
repo: tool.schema.string().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('问题标签,多个用逗号分隔'),
|
||||||
|
page: tool.schema.number().optional().describe('分页页码,默认: 1'),
|
||||||
|
page_size: tool.schema.number().optional().describe('分页每页大小,默认: 30'),
|
||||||
|
order_by: tool.schema.string().optional().describe('排序方式,如 created_at, -updated_at'),
|
||||||
|
},
|
||||||
|
summary: '查询 Issue 列表',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).define(async (ctx) => {
|
||||||
|
const repo = ctx.query?.repo;
|
||||||
|
const state = ctx.query?.state;
|
||||||
|
const keyword = ctx.query?.keyword;
|
||||||
|
const labels = ctx.query?.labels;
|
||||||
|
const page = ctx.query?.page ? Number(ctx.query.page) : undefined;
|
||||||
|
const page_size = ctx.query?.page_size ? Number(ctx.query.page_size) : undefined;
|
||||||
|
const order_by = ctx.query?.order_by;
|
||||||
|
|
||||||
|
if (!repo) {
|
||||||
|
ctx.throw(400, '缺少参数 repo');
|
||||||
|
}
|
||||||
|
|
||||||
|
const params: Record<string, any> = {};
|
||||||
|
if (state) params.state = state;
|
||||||
|
if (keyword) params.keyword = keyword;
|
||||||
|
if (labels) params.labels = labels;
|
||||||
|
if (page) params.page = page;
|
||||||
|
if (page_size) params.page_size = page_size;
|
||||||
|
if (order_by) params.order_by = order_by;
|
||||||
|
|
||||||
|
const res = await cnb.issue.getList(repo, params);
|
||||||
|
ctx.forward(res);
|
||||||
|
}).addTo(app);
|
||||||
142
agent/routes/knowledge/ai.ts
Normal file
142
agent/routes/knowledge/ai.ts
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
import { createSkill, tool } from '@kevisual/router';
|
||||||
|
import { app, cnb } from '../../app.ts';
|
||||||
|
import { CNBChat } from '@kevisual/ai/browser'
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
调用cnb-ai-chat技能, repo为kevisual/starred-auto.
|
||||||
|
问题是:用户提供的问题是OpenListTeam/OpenList是什么,有多少star
|
||||||
|
|
||||||
|
*/
|
||||||
|
app.route({
|
||||||
|
path: 'cnb',
|
||||||
|
key: 'cnb-ai-chat',
|
||||||
|
description: '调用cnb的知识库ai对话功能进行聊天',
|
||||||
|
middleware: ['admin-auth'],
|
||||||
|
metadata: {
|
||||||
|
tags: ['opencode'],
|
||||||
|
...createSkill({
|
||||||
|
skill: 'cnb-ai-chat',
|
||||||
|
title: '调用cnb的知识库ai对话功能进行聊天',
|
||||||
|
summary: '调用cnb的知识库ai对话功能进行聊天,基于cnb提供的ai能力',
|
||||||
|
args: {
|
||||||
|
question: tool.schema.string().describe('用户输入的消息内容'),
|
||||||
|
repo: tool.schema.string().optional().describe('知识库仓库ID,默认为空表示使用默认知识库'),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).define(async (ctx) => {
|
||||||
|
const question = ctx.query?.question;
|
||||||
|
if (!question) {
|
||||||
|
ctx.body = { content: '请提供有效的消息内容' };
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let repo = ctx.query?.repo;
|
||||||
|
if (!repo) {
|
||||||
|
// 如果未指定知识库仓库ID,则使用默认知识库
|
||||||
|
const res = await cnb.repo.getRepoList({ flags: 'KnowledgeBase' });
|
||||||
|
if (res.code === 200 && res.data.length > 0) {
|
||||||
|
repo = res.data[0].path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log("Using knowledge base repo:", repo);
|
||||||
|
const ragRes = await cnb.knowledgeBase.queryKnowledgeBase(repo || '', {
|
||||||
|
query: question,
|
||||||
|
score_threshold: 0.62,
|
||||||
|
top_k: 10,
|
||||||
|
});
|
||||||
|
if (ragRes.code !== 200) {
|
||||||
|
ctx.body = { content: `查询知识库失败,错误信息:${ragRes.message}` };
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const list = ragRes.data || [];
|
||||||
|
// 构建RAG上下文,包含文件来源和相似度信息
|
||||||
|
const ragContext = list.map((item, index) => {
|
||||||
|
const source = item.metadata?.path || item.metadata?.name || '未知来源';
|
||||||
|
const type = item.metadata?.type === 'code' ? '〔代码〕' : '〔文档〕';
|
||||||
|
const scorePercent = Math.round((item.score || 0) * 100);
|
||||||
|
const url = item.metadata?.url || '无';
|
||||||
|
return `〔来源${index + 1}〕${type} ${source} (相似度: ${scorePercent}%)\n${item.chunk}\n访问地址: ${url}`;
|
||||||
|
}).join('\n\n---\n\n');
|
||||||
|
// hunyuan-a13b
|
||||||
|
// enable_thinking
|
||||||
|
const chat = new CNBChat({
|
||||||
|
repo,
|
||||||
|
token: cnb.token,
|
||||||
|
model: 'hunyuan-a13b'
|
||||||
|
});
|
||||||
|
const messages = [
|
||||||
|
{
|
||||||
|
role: 'system',
|
||||||
|
content: `[角色定义]='''\n你是一个专业的技术助手,擅长基于提供的知识库内容进行准确、有条理的分析和回答。你的特点是:\n1. 严格基于RAG检索到的上下文内容进行回答,不添加未经验证的信息\n2. 回答时清晰标注信息来源,便于用户追溯查证\n3. 面对不确定的信息,明确标注「根据提供的内容无法确定」\n4. 代码相关问题注重可执行性和最佳实践\n'''[要求]='''\n1. 严格遵循用户的提问要求,优先解决用户的核心问题\n2. 避免侵犯版权的内容,不复制原文超过100字(技术术语和函数名除外)\n3. 使用中文进行响应,语言专业且易于理解\n4. 如果上下文存在多个来源,优先使用相似度更高的内容\n5. 对于代码片段,确保完整且可直接使用\n6. 当上下文中没有相关信息时,直接说明「知识库中未找到相关内容」\n7. 在思考过程中分析:用户的真实意图是什么?提供的上下文是否足够回答?\n'''[回答格式]='''\n- 先简要说明回答的核心结论\n- 如有必要,分点阐述详细分析过程\n- 标注关键信息来源(标注【来源X】即可)\n- 提供可操作的建议或代码示例\n'''`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: 'user',
|
||||||
|
content: `[上下文]='''\n${ragContext}\n'''\n\n[用户问题]='''\n${question}\n'''\n\n请基于以上上下文知识库内容回答用户问题。`
|
||||||
|
}
|
||||||
|
] as Array<{ role: 'system' | 'user' | 'assistant', content: string }>;
|
||||||
|
const response = await chat.chat({
|
||||||
|
messages
|
||||||
|
});
|
||||||
|
const txt = chat.responseText;
|
||||||
|
ctx.body = { content: txt, response };
|
||||||
|
}).addTo(app);
|
||||||
|
|
||||||
|
|
||||||
|
// RAG知识库查询技能: 查询openlist有多少star
|
||||||
|
app.route({
|
||||||
|
path: 'cnb',
|
||||||
|
key: 'cnb-rag-query',
|
||||||
|
description: '调用cnb的知识库RAG查询功能进行问答',
|
||||||
|
middleware: ['admin-auth'],
|
||||||
|
metadata: {
|
||||||
|
tags: ['opencode'],
|
||||||
|
...createSkill({
|
||||||
|
skill: 'cnb-rag-query',
|
||||||
|
title: '调用cnb的知识库RAG查询功能进行问答',
|
||||||
|
summary: '调用cnb的知识库RAG查询功能进行问答,基于cnb提供的知识库能力',
|
||||||
|
args: {
|
||||||
|
question: tool.schema.string().describe('用户输入的消息内容'),
|
||||||
|
repo: tool.schema.string().optional().describe('知识库仓库ID,默认为空表示使用默认知识库'),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).define(async (ctx) => {
|
||||||
|
const question = ctx.query?.question;
|
||||||
|
if (!question) {
|
||||||
|
ctx.body = { content: '请提供有效的消息内容' };
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let repo = ctx.query?.repo;
|
||||||
|
if (!repo) {
|
||||||
|
// 如果未指定知识库仓库ID,则使用默认知识库
|
||||||
|
const res = await cnb.repo.getRepoList({ flags: 'KnowledgeBase' });
|
||||||
|
if (res.code === 200 && res.data.length > 0) {
|
||||||
|
repo = res.data[0].path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log("Using knowledge base repo:", repo);
|
||||||
|
const ragRes = await cnb.knowledgeBase.queryKnowledgeBase(repo || '', {
|
||||||
|
query: question,
|
||||||
|
score_threshold: 0.62,
|
||||||
|
top_k: 10,
|
||||||
|
});
|
||||||
|
if (ragRes.code !== 200) {
|
||||||
|
ctx.body = { content: `查询知识库失败,错误信息:${ragRes.message}` };
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const list = ragRes.data || [];
|
||||||
|
let answer = `基于知识库「${repo}」的查询结果:\n\n`;
|
||||||
|
if (list.length === 0) {
|
||||||
|
answer += '知识库中未找到相关内容。';
|
||||||
|
} else {
|
||||||
|
list.forEach((item, index) => {
|
||||||
|
const source = item.metadata?.path || item.metadata?.name || '未知来源';
|
||||||
|
const type = item.metadata?.type === 'code' ? '〔代码〕' : '〔文档〕';
|
||||||
|
const scorePercent = Math.round((item.score || 0) * 100);
|
||||||
|
const url = item.metadata?.url || '无';
|
||||||
|
answer += `【来源${index + 1}】${type} ${source} (相似度: ${scorePercent}%)\n${item.chunk}\n访问地址: ${url}\n\n`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ctx.body = { content: answer };
|
||||||
|
}).addTo(app);
|
||||||
1
agent/routes/knowledge/index.ts
Normal file
1
agent/routes/knowledge/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import './ai.ts'
|
||||||
@@ -2,27 +2,35 @@ import { createSkill } from '@kevisual/router';
|
|||||||
import { app, cnb } from '../../app.ts';
|
import { app, cnb } from '../../app.ts';
|
||||||
import { tool } from "@opencode-ai/plugin/tool"
|
import { tool } from "@opencode-ai/plugin/tool"
|
||||||
|
|
||||||
|
// "列出我的代码仓库,search blog"
|
||||||
|
// 列出我的知识库的代码仓库
|
||||||
app.route({
|
app.route({
|
||||||
path: 'cnb',
|
path: 'cnb',
|
||||||
key: 'list-repos',
|
key: 'list-repos',
|
||||||
description: '列出我的代码仓库',
|
description: '列出我的代码仓库',
|
||||||
middleware: ['auth'],
|
middleware: ['admin-auth'],
|
||||||
metadata: {
|
metadata: {
|
||||||
tags: ['opencode'],
|
tags: ['opencode'],
|
||||||
...createSkill({
|
...createSkill({
|
||||||
skill: 'list-repos',
|
skill: 'list-repos',
|
||||||
title: '列出代码仓库',
|
title: '列出cnb代码仓库',
|
||||||
summary: '列出代码仓库',
|
summary: '列出cnb代码仓库, 可选flags参数,如 KnowledgeBase',
|
||||||
args: {
|
args: {
|
||||||
search: tool.schema.string().optional().describe('搜索关键词'),
|
search: tool.schema.string().optional().describe('搜索关键词'),
|
||||||
pageSize: tool.schema.number().optional().describe('每页数量,默认999'),
|
pageSize: tool.schema.number().optional().describe('每页数量,默认999'),
|
||||||
|
flags: tool.schema.string().optional().describe('仓库标记,如果是知识库则填写 KnowledgeBase'),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}).define(async (ctx) => {
|
}).define(async (ctx) => {
|
||||||
const search = ctx.query?.search;
|
const search = ctx.query?.search;
|
||||||
const pageSize = ctx.query?.pageSize || 9999;
|
const pageSize = ctx.query?.pageSize || 9999;
|
||||||
const res = await cnb.repo.getRepoList({ search, page_size: pageSize, role: 'developer' });
|
const flags = ctx.query?.flags;
|
||||||
|
const params: any = {};
|
||||||
|
if (flags) {
|
||||||
|
params.flags = flags;
|
||||||
|
}
|
||||||
|
const res = await cnb.repo.getRepoList({ search, page_size: pageSize, role: 'developer', ...params });
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
const repos = res.data.map((item) => ({
|
const repos = res.data.map((item) => ({
|
||||||
name: item.name,
|
name: item.name,
|
||||||
@@ -30,7 +38,7 @@ app.route({
|
|||||||
description: item.description,
|
description: item.description,
|
||||||
web_url: item.web_url,
|
web_url: item.web_url,
|
||||||
}));
|
}));
|
||||||
ctx.body = { content: JSON.stringify(repos) };
|
ctx.body = { content: JSON.stringify(repos), list: res.data };
|
||||||
} else {
|
} else {
|
||||||
ctx.throw(500, '获取仓库列表失败');
|
ctx.throw(500, '获取仓库列表失败');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import { app, cnb } from '../../app.ts';
|
import { app, cnb } from '../../app.ts';
|
||||||
import { createSkill, Skill } from '@kevisual/router'
|
import { createSkill, Skill } from '@kevisual/router'
|
||||||
import { tool } from "@opencode-ai/plugin/tool"
|
import { tool } from "@opencode-ai/plugin/tool"
|
||||||
|
|
||||||
|
// 创建一个仓库 kevisual/test-repo
|
||||||
app.route({
|
app.route({
|
||||||
path: 'cnb',
|
path: 'cnb',
|
||||||
key: 'create-repo',
|
key: 'create-repo',
|
||||||
description: '创建代码仓库, 参数name, visibility, description',
|
description: '创建代码仓库, 参数name, visibility, description',
|
||||||
middleware: ['auth'],
|
middleware: ['admin-auth'],
|
||||||
metadata: {
|
metadata: {
|
||||||
tags: ['opencode'],
|
tags: ['opencode'],
|
||||||
...createSkill({
|
...createSkill({
|
||||||
@@ -45,7 +47,7 @@ app.route({
|
|||||||
path: 'cnb',
|
path: 'cnb',
|
||||||
key: 'create-repo-file',
|
key: 'create-repo-file',
|
||||||
description: '在代码仓库中创建文件, repoName, filePath, content, encoding',
|
description: '在代码仓库中创建文件, repoName, filePath, content, encoding',
|
||||||
middleware: ['auth'],
|
middleware: ['admin-auth'],
|
||||||
metadata: {
|
metadata: {
|
||||||
tags: ['opencode'],
|
tags: ['opencode'],
|
||||||
...createSkill({
|
...createSkill({
|
||||||
@@ -79,12 +81,12 @@ app.route({
|
|||||||
ctx.forward(res);
|
ctx.forward(res);
|
||||||
}).addTo(app);
|
}).addTo(app);
|
||||||
|
|
||||||
|
// 删除一个仓库 kevisual/test-repo
|
||||||
app.route({
|
app.route({
|
||||||
path: 'cnb',
|
path: 'cnb',
|
||||||
key: 'delete-repo',
|
key: 'delete-repo',
|
||||||
description: '删除代码仓库, 参数name',
|
description: '删除代码仓库, 参数name',
|
||||||
middleware: ['auth'],
|
middleware: ['admin-auth'],
|
||||||
metadata: {
|
metadata: {
|
||||||
tags: ['opencode'],
|
tags: ['opencode'],
|
||||||
...createSkill({
|
...createSkill({
|
||||||
|
|||||||
@@ -1,12 +1,27 @@
|
|||||||
|
import { createSkill, tool } from '@kevisual/router';
|
||||||
import { app, cnb } from '../../app.ts';
|
import { app, cnb } from '../../app.ts';
|
||||||
|
import z from 'zod';
|
||||||
|
import './skills.ts';
|
||||||
|
import './keep.ts';
|
||||||
|
|
||||||
|
// 启动工作空间
|
||||||
app.route({
|
app.route({
|
||||||
path: 'cnb',
|
path: 'cnb',
|
||||||
key: 'start-workspace',
|
key: 'start-workspace',
|
||||||
description: '启动开发工作空间, 参数 repo',
|
description: '启动开发工作空间, 参数 repo',
|
||||||
middleware: ['auth'],
|
middleware: ['admin-auth'],
|
||||||
metadata: {
|
metadata: {
|
||||||
tags: ['opencode']
|
tags: ['opencode'],
|
||||||
|
...createSkill({
|
||||||
|
skill: 'start-workspace',
|
||||||
|
title: '启动cnb工作空间',
|
||||||
|
summary: '启动cnb工作空间',
|
||||||
|
args: {
|
||||||
|
repo: tool.schema.string().describe('代码仓库路径,例如 user/repo'),
|
||||||
|
branch: tool.schema.string().optional().describe('分支名称,默认主分支'),
|
||||||
|
ref: tool.schema.string().optional().describe('提交引用,例如 commit sha'),
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}).define(async (ctx) => {
|
}).define(async (ctx) => {
|
||||||
const repo = ctx.query?.repo;
|
const repo = ctx.query?.repo;
|
||||||
@@ -21,3 +36,133 @@ app.route({
|
|||||||
});
|
});
|
||||||
ctx.forward(res);
|
ctx.forward(res);
|
||||||
}).addTo(app);
|
}).addTo(app);
|
||||||
|
|
||||||
|
// 获取cnb工作空间列表
|
||||||
|
app.route({
|
||||||
|
path: 'cnb',
|
||||||
|
key: 'list-workspace',
|
||||||
|
description: '获取cnb开发工作空间列表,可选参数 status=running 获取运行中的环境',
|
||||||
|
middleware: ['admin-auth'],
|
||||||
|
metadata: {
|
||||||
|
tags: ['opencode'],
|
||||||
|
...createSkill({
|
||||||
|
skill: 'list-workspace',
|
||||||
|
title: '列出cnb工作空间',
|
||||||
|
summary: '列出cnb工作空间列表,支持按状态过滤, status 可选值 running 或 closed',
|
||||||
|
args: {
|
||||||
|
status: tool.schema.string().optional().describe('开发环境状态,running: 运行中,closed: 已关闭和停止的'),
|
||||||
|
page: tool.schema.number().optional().describe('分页页码,默认 1'),
|
||||||
|
pageSize: tool.schema.number().optional().describe('分页大小,默认 20,最大 100'),
|
||||||
|
slug: tool.schema.string().optional().describe('仓库路径,例如 groupname/reponame'),
|
||||||
|
branch: tool.schema.string().optional().describe('分支名称'),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).define(async (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 });
|
||||||
|
}).addTo(app);
|
||||||
|
|
||||||
|
// 获取工作空间详情
|
||||||
|
app.route({
|
||||||
|
path: 'cnb',
|
||||||
|
key: 'get-workspace',
|
||||||
|
description: '获取工作空间详情,通过 repo 和 sn 获取',
|
||||||
|
middleware: ['admin-auth'],
|
||||||
|
metadata: {
|
||||||
|
tags: ['opencode'],
|
||||||
|
...createSkill({
|
||||||
|
skill: 'get-workspace',
|
||||||
|
title: '获取工作空间详情',
|
||||||
|
summary: '获取工作空间详细信息',
|
||||||
|
args: {
|
||||||
|
repo: tool.schema.string().describe('代码仓库路径,例如 user/repo'),
|
||||||
|
sn: tool.schema.string().describe('工作空间流水线的 sn'),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).define(async (ctx) => {
|
||||||
|
const repo = ctx.query?.repo;
|
||||||
|
const sn = ctx.query?.sn;
|
||||||
|
if (!repo) {
|
||||||
|
ctx.throw(400, '缺少参数 repo');
|
||||||
|
}
|
||||||
|
if (!sn) {
|
||||||
|
ctx.throw(400, '缺少参数 sn');
|
||||||
|
}
|
||||||
|
const res = await cnb.workspace.getDetail(repo, sn);
|
||||||
|
ctx.forward({ code: 200, message: 'success', data: res });
|
||||||
|
}).addTo(app);
|
||||||
|
|
||||||
|
// 删除工作空间
|
||||||
|
app.route({
|
||||||
|
path: 'cnb',
|
||||||
|
key: 'delete-workspace',
|
||||||
|
description: '删除工作空间,通过 pipelineId 或 sn',
|
||||||
|
middleware: ['admin-auth'],
|
||||||
|
metadata: {
|
||||||
|
tags: ['opencode'],
|
||||||
|
...createSkill({
|
||||||
|
skill: 'delete-workspace',
|
||||||
|
title: '删除工作空间',
|
||||||
|
summary: '删除工作空间,pipelineId 和 sn 二选一',
|
||||||
|
args: {
|
||||||
|
pipelineId: tool.schema.string().optional().describe('流水线 ID,优先使用'),
|
||||||
|
sn: tool.schema.string().optional().describe('流水线构建号'),
|
||||||
|
sns: tool.schema.array(z.string()).optional().describe('批量流水线构建号'),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).define(async (ctx) => {
|
||||||
|
const pipelineId = ctx.query?.pipelineId;
|
||||||
|
const sn = ctx.query?.sn;
|
||||||
|
const sns = ctx.query?.sns;
|
||||||
|
if (!pipelineId && !sn && (!sns || sns.length === 0)) {
|
||||||
|
ctx.throw(400, 'pipelineId 和 sn 必须提供其中一个');
|
||||||
|
}
|
||||||
|
if (sns && sns.length > 0) {
|
||||||
|
const results = [];
|
||||||
|
for (const snItem of sns) {
|
||||||
|
const res = await cnb.workspace.deleteWorkspace({ sn: snItem });
|
||||||
|
results.push(res);
|
||||||
|
}
|
||||||
|
ctx.forward({ code: 200, message: 'success', data: results });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const res = await cnb.workspace.deleteWorkspace({ pipelineId, sn });
|
||||||
|
ctx.forward(res);
|
||||||
|
}).addTo(app);
|
||||||
|
|
||||||
|
// 停止工作空间
|
||||||
|
app.route({
|
||||||
|
path: 'cnb',
|
||||||
|
key: 'stop-workspace',
|
||||||
|
description: '停止工作空间,通过 pipelineId 或 sn',
|
||||||
|
middleware: ['admin-auth'],
|
||||||
|
metadata: {
|
||||||
|
tags: ['opencode'],
|
||||||
|
...createSkill({
|
||||||
|
skill: 'stop-workspace',
|
||||||
|
title: '停止工作空间',
|
||||||
|
summary: '停止运行中的工作空间',
|
||||||
|
args: {
|
||||||
|
pipelineId: tool.schema.string().optional().describe('流水线 ID,优先使用'),
|
||||||
|
sn: tool.schema.string().optional().describe('流水线构建号'),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).define(async (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 });
|
||||||
|
}).addTo(app);
|
||||||
|
|
||||||
|
|||||||
214
agent/routes/workspace/keep.ts
Normal file
214
agent/routes/workspace/keep.ts
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
import { createSkill, tool } from '@kevisual/router';
|
||||||
|
import { app, cnb } from '../../app.ts';
|
||||||
|
import { nanoid } from 'nanoid';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import { createKeepAlive } from '../../../src/keep.ts';
|
||||||
|
|
||||||
|
type AliveInfo = {
|
||||||
|
startTime: number;
|
||||||
|
updatedTime?: number;
|
||||||
|
KeepAlive: ReturnType<typeof createKeepAlive>;
|
||||||
|
id: string;// 6位唯一标识符
|
||||||
|
}
|
||||||
|
|
||||||
|
const keepAliveMap = new Map<string, AliveInfo>();
|
||||||
|
|
||||||
|
// 保持工作空间存活技能
|
||||||
|
app.route({
|
||||||
|
path: 'cnb',
|
||||||
|
key: 'keep-workspace-alive',
|
||||||
|
description: '保持工作空间存活技能,参数wsUrl:工作空间访问URL,cookie:访问工作空间所需的cookie',
|
||||||
|
middleware: ['admin-auth'],
|
||||||
|
metadata: {
|
||||||
|
tags: [],
|
||||||
|
...({
|
||||||
|
args: {
|
||||||
|
wsUrl: tool.schema.string().describe('工作空间的访问URL'),
|
||||||
|
cookie: tool.schema.string().describe('访问工作空间所需的cookie')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).define(async (ctx) => {
|
||||||
|
const wsUrl = ctx.query?.wsUrl as string;
|
||||||
|
const cookie = ctx.query?.cookie as string;
|
||||||
|
if (!wsUrl) {
|
||||||
|
ctx.throw(400, '缺少工作空间访问URL参数');
|
||||||
|
}
|
||||||
|
if (!cookie) {
|
||||||
|
ctx.throw(400, '缺少访问工作空间所需的cookie参数');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测是否已在运行(通过 wsUrl 遍历检查)
|
||||||
|
const existing = Array.from(keepAliveMap.values()).find(info => (info as AliveInfo).id && (info as any).KeepAlive?.wsUrl === wsUrl);
|
||||||
|
if (existing) {
|
||||||
|
ctx.body = { message: `工作空间 ${wsUrl} 的保持存活任务已在运行中`, id: (existing as AliveInfo).id };
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`启动保持工作空间 ${wsUrl} 存活的任务`);
|
||||||
|
const keep = createKeepAlive({
|
||||||
|
wsUrl,
|
||||||
|
cookie,
|
||||||
|
onConnect: () => {
|
||||||
|
console.log(`工作空间 ${wsUrl} 保持存活任务已连接`);
|
||||||
|
},
|
||||||
|
onMessage: (data) => {
|
||||||
|
// 可选:处理收到的消息
|
||||||
|
// console.log(`工作空间 ${wsUrl} 收到消息: ${data}`);
|
||||||
|
// 通过 wsUrl 找到对应的 id 并更新时间
|
||||||
|
for (const info of keepAliveMap.values()) {
|
||||||
|
if ((info as any).KeepAlive?.wsUrl === wsUrl) {
|
||||||
|
info.updatedTime = Date.now();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
debug: true,
|
||||||
|
onExit: (code) => {
|
||||||
|
console.log(`工作空间 ${wsUrl} 保持存活任务已退出,退出码: ${code}`);
|
||||||
|
// 通过 wsUrl 找到对应的 id 并删除
|
||||||
|
for (const [id, info] of keepAliveMap.entries()) {
|
||||||
|
if ((info as any).KeepAlive?.wsUrl === wsUrl) {
|
||||||
|
keepAliveMap.delete(id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const id = nanoid(6).toLowerCase();
|
||||||
|
keepAliveMap.set(id, { startTime: Date.now(), updatedTime: Date.now(), KeepAlive: keep, id });
|
||||||
|
|
||||||
|
ctx.body = { content: `已启动保持工作空间 ${wsUrl} 存活的任务`, id };
|
||||||
|
}).addTo(app);
|
||||||
|
|
||||||
|
// 获取保持工作空间存活任务列表技能
|
||||||
|
app.route({
|
||||||
|
path: 'cnb',
|
||||||
|
key: 'list-keep-alive-tasks',
|
||||||
|
description: '获取保持工作空间存活任务列表技能',
|
||||||
|
middleware: ['admin-auth'],
|
||||||
|
metadata: {
|
||||||
|
tags: [],
|
||||||
|
}
|
||||||
|
}).define(async (ctx) => {
|
||||||
|
const list = Array.from(keepAliveMap.entries()).map(([id, info]) => {
|
||||||
|
const now = Date.now();
|
||||||
|
const duration = Math.floor((now - info.startTime) / 60000); // 分钟
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
wsUrl: (info as any).KeepAlive?.wsUrl,
|
||||||
|
startTime: info.startTime,
|
||||||
|
startTimeStr: dayjs(info.startTime).format('YYYY-MM-DD HH:mm'),
|
||||||
|
updatedTime: info.updatedTime,
|
||||||
|
updatedTimeStr: dayjs(info.updatedTime).format('YYYY-MM-DD HH:mm'),
|
||||||
|
duration,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ctx.body = { list };
|
||||||
|
}).addTo(app);
|
||||||
|
|
||||||
|
// 停止保持工作空间存活技能
|
||||||
|
app.route({
|
||||||
|
path: 'cnb',
|
||||||
|
key: 'stop-keep-workspace-alive',
|
||||||
|
description: '停止保持工作空间存活技能, 参数wsUrl:工作空间访问URL或者id',
|
||||||
|
middleware: ['admin-auth'],
|
||||||
|
metadata: {
|
||||||
|
tags: [],
|
||||||
|
...({
|
||||||
|
args: {
|
||||||
|
wsUrl: tool.schema.string().optional().describe('工作空间的访问URL'),
|
||||||
|
id: tool.schema.string().optional().describe('保持存活任务的唯一标识符'),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).define(async (ctx) => {
|
||||||
|
const wsUrl = ctx.query?.wsUrl as string;
|
||||||
|
const id = ctx.query?.id as string;
|
||||||
|
if (!wsUrl && !id) {
|
||||||
|
ctx.throw(400, '缺少工作空间访问URL参数或唯一标识符');
|
||||||
|
}
|
||||||
|
|
||||||
|
let targetId: string | undefined;
|
||||||
|
let wsUrlFound: string | undefined;
|
||||||
|
|
||||||
|
if (id) {
|
||||||
|
const info = keepAliveMap.get(id);
|
||||||
|
if (info) {
|
||||||
|
targetId = id;
|
||||||
|
wsUrlFound = (info as any).KeepAlive?.wsUrl;
|
||||||
|
}
|
||||||
|
} else if (wsUrl) {
|
||||||
|
for (const [key, info] of keepAliveMap.entries()) {
|
||||||
|
if ((info as any).KeepAlive?.wsUrl === wsUrl) {
|
||||||
|
targetId = key;
|
||||||
|
wsUrlFound = wsUrl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetId) {
|
||||||
|
const keepAlive = keepAliveMap.get(targetId);
|
||||||
|
const endTime = Date.now();
|
||||||
|
const duration = endTime - keepAlive!.startTime;
|
||||||
|
keepAlive?.KeepAlive?.disconnect();
|
||||||
|
keepAliveMap.delete(targetId);
|
||||||
|
ctx.body = { content: `已停止保持工作空间 ${wsUrlFound} 存活的任务,持续时间: ${duration}ms`, id: targetId };
|
||||||
|
} else {
|
||||||
|
ctx.body = { content: `没有找到对应的工作空间保持存活任务` };
|
||||||
|
}
|
||||||
|
}).addTo(app);
|
||||||
|
|
||||||
|
app.route({
|
||||||
|
path: 'cnb',
|
||||||
|
key: 'reset-keep-workspace-alive',
|
||||||
|
description: '对存活的工作空间,startTime进行重置',
|
||||||
|
middleware: ['admin-auth'],
|
||||||
|
metadata: {
|
||||||
|
tags: [],
|
||||||
|
}
|
||||||
|
}).define(async (ctx) => {
|
||||||
|
const now = Date.now();
|
||||||
|
for (const info of keepAliveMap.values()) {
|
||||||
|
info.startTime = now;
|
||||||
|
}
|
||||||
|
ctx.body = { content: `已重置所有存活工作空间的开始时间` };
|
||||||
|
}).addTo(app);
|
||||||
|
|
||||||
|
app.route({
|
||||||
|
path: 'cnb',
|
||||||
|
key: 'clear-keep-workspace-alive',
|
||||||
|
description: '对存活的工作空间,超过5小时的进行清理',
|
||||||
|
middleware: ['admin-auth'],
|
||||||
|
metadata: {
|
||||||
|
tags: [],
|
||||||
|
}
|
||||||
|
}).define(async (ctx) => {
|
||||||
|
const res = clearKeepAlive();
|
||||||
|
ctx.body = {
|
||||||
|
content: `已清理所有存活工作空间中超过5小时的任务` + (res.length ? `,清理项:${res.map(i => i.wsUrl).join(', ')}` : ''),
|
||||||
|
list: res
|
||||||
|
};
|
||||||
|
}).addTo(app);
|
||||||
|
|
||||||
|
const clearKeepAlive = () => {
|
||||||
|
const now = Date.now();
|
||||||
|
let clearedArr: { id: string; wsUrl: string }[] = [];
|
||||||
|
for (const [id, info] of keepAliveMap.entries()) {
|
||||||
|
if (now - info.startTime > FIVE_HOURS) {
|
||||||
|
console.log(`工作空间 ${(info as any).KeepAlive?.wsUrl} 超过5小时,自动停止`);
|
||||||
|
info.KeepAlive?.disconnect?.();
|
||||||
|
keepAliveMap.delete(id);
|
||||||
|
clearedArr.push({ id, wsUrl: (info as any).KeepAlive?.wsUrl });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return clearedArr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 每5小时自动清理超时的keepAlive任务
|
||||||
|
const FIVE_HOURS = 5 * 60 * 60 * 1000;
|
||||||
|
setInterval(() => {
|
||||||
|
clearKeepAlive();
|
||||||
|
}, FIVE_HOURS);
|
||||||
64
agent/routes/workspace/skills.ts
Normal file
64
agent/routes/workspace/skills.ts
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import { createSkill, tool } from '@kevisual/router';
|
||||||
|
import { app, cnb } from '../../app.ts';
|
||||||
|
|
||||||
|
// 批量删除已停止的cnb工作空间
|
||||||
|
// app.route({
|
||||||
|
// path: 'cnb',
|
||||||
|
// key: 'clean-closed-workspace-skill',
|
||||||
|
// description: '批量删除已停止的cnb工作空间',
|
||||||
|
// middleware: ['auth'],
|
||||||
|
// metadata: {
|
||||||
|
// tags: ['opencode'],
|
||||||
|
// ...createSkill({
|
||||||
|
// skill: 'clean-closed-workspace-skill',
|
||||||
|
// title: '清理已关闭的cnb工作空间',
|
||||||
|
// summary: '批量删除已停止的cnb工作空间,释放资源',
|
||||||
|
// args: {
|
||||||
|
// question: tool.schema.string().optional().describe('具体的要求的信息'),
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// }).define(async (ctx) => {
|
||||||
|
// const question = ctx.query?.question || '';
|
||||||
|
// let content = `这是一个技能任务, 批量删除已停止的cnb工作空间,释放资源
|
||||||
|
// 执行步骤:
|
||||||
|
// 1. 执行list-workspace,获取状态为 closed 的工作空间列表,提取sn
|
||||||
|
// 2. 执行delete-workspace技能,传入sns列表的数组,批量删除工作空间`
|
||||||
|
// if (question) {
|
||||||
|
// content += `\n注意用户的具体要求是:${question}`;
|
||||||
|
// }
|
||||||
|
// ctx.body = { content }
|
||||||
|
// }).addTo(app);
|
||||||
|
|
||||||
|
// 批量删除已停止的cnb工作空间
|
||||||
|
app.route({
|
||||||
|
path: 'cnb',
|
||||||
|
key: 'clean-closed-workspace',
|
||||||
|
description: '批量删除已停止的cnb工作空间',
|
||||||
|
middleware: ['admin-auth'],
|
||||||
|
metadata: {
|
||||||
|
tags: ['opencode'],
|
||||||
|
...createSkill({
|
||||||
|
skill: 'clean-closed-workspace',
|
||||||
|
title: '清理已关闭的cnb工作空间',
|
||||||
|
summary: '批量删除已停止的cnb工作空间,释放资源',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).define(async (ctx) => {
|
||||||
|
const closedWorkspaces = await cnb.workspace.list({ status: 'closed' });
|
||||||
|
if (closedWorkspaces.code !== 200) {
|
||||||
|
ctx.throw(500, '获取已关闭工作空间列表失败');
|
||||||
|
}
|
||||||
|
const list = closedWorkspaces.data?.list || [];
|
||||||
|
if (list.length === 0) {
|
||||||
|
ctx.forward({ code: 200, message: '没有已关闭的工作空间需要删除', data: [] });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const sns = list.map(ws => ws.sn);
|
||||||
|
const results = [];
|
||||||
|
for (const sn of sns) {
|
||||||
|
const res = await cnb.workspace.deleteWorkspace({ sn });
|
||||||
|
results.push(res);
|
||||||
|
}
|
||||||
|
ctx.forward({ code: 200, message: '已关闭的工作空间删除完成', data: results });
|
||||||
|
}).addTo(app);
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { resolvePath } from '@kevisual/use-config';
|
||||||
|
import { execSync } from 'node:child_process';
|
||||||
|
|
||||||
|
const buildFn = async (opts: { entry?: string, naming?: string }) => {
|
||||||
|
const entry = opts.entry || 'agent/opencode.ts';
|
||||||
|
const naming = opts.naming || 'opencode';
|
||||||
|
const external: string[] = ["bun", "ws"];
|
||||||
|
await Bun.build({
|
||||||
|
target: 'node',
|
||||||
|
format: 'esm',
|
||||||
|
entrypoints: [resolvePath(entry, { meta: import.meta })],
|
||||||
|
outdir: resolvePath('./dist', { meta: import.meta }),
|
||||||
|
naming: {
|
||||||
|
entry: `${naming}.js`,
|
||||||
|
},
|
||||||
|
external,
|
||||||
|
});
|
||||||
|
const cmd = `dts -i ${entry} -o ${naming}.d.ts`;
|
||||||
|
execSync(cmd);
|
||||||
|
};
|
||||||
|
|
||||||
|
await buildFn({ naming: 'opencode', entry: 'agent/opencode.ts' });
|
||||||
|
await buildFn({ naming: 'keep', entry: 'src/keep.ts' });
|
||||||
|
await buildFn({ naming: 'routes', entry: 'agent/index.ts' });
|
||||||
39
package.json
39
package.json
@@ -1,38 +1,55 @@
|
|||||||
{
|
{
|
||||||
"name": "@kevisual/cnb",
|
"name": "@kevisual/cnb",
|
||||||
"version": "0.0.1",
|
"version": "0.0.13",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"build": "bun run bun.config.ts"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"files": [
|
"files": [
|
||||||
|
"dist",
|
||||||
"src",
|
"src",
|
||||||
"mod.ts",
|
"mod.ts",
|
||||||
"agent"
|
"agent"
|
||||||
],
|
],
|
||||||
"author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
|
"author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"packageManager": "pnpm@10.28.0",
|
"packageManager": "pnpm@10.28.2",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@kevisual/ai": "^0.0.24",
|
||||||
"@kevisual/context": "^0.0.4",
|
"@kevisual/context": "^0.0.4",
|
||||||
"@kevisual/types": "^0.0.11",
|
"@kevisual/types": "^0.0.12",
|
||||||
"@opencode-ai/plugin": "^1.1.23",
|
"@opencode-ai/plugin": "^1.1.44",
|
||||||
"@types/bun": "^1.3.6",
|
"@types/bun": "^1.3.8",
|
||||||
"@types/node": "^25.0.9",
|
"@types/node": "^25.1.0",
|
||||||
|
"@types/ws": "^8.18.1",
|
||||||
|
"dayjs": "^1.11.19",
|
||||||
"dotenv": "^17.2.3"
|
"dotenv": "^17.2.3"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
|
"resolutions": {
|
||||||
|
"zod": "^4.3.6"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kevisual/query": "^0.0.35",
|
"@kevisual/query": "^0.0.38",
|
||||||
"@kevisual/router": "^0.0.55",
|
"@kevisual/router": "^0.0.64",
|
||||||
"@kevisual/use-config": "^1.0.28",
|
"@kevisual/use-config": "^1.0.28",
|
||||||
"es-toolkit": "^1.43.0",
|
"es-toolkit": "^1.44.0",
|
||||||
"nanoid": "^5.1.6",
|
"nanoid": "^5.1.6",
|
||||||
"zod": "^4.3.5"
|
"unstorage": "^1.17.4",
|
||||||
|
"ws": "npm:@kevisual/ws",
|
||||||
|
"zod": "^4.3.6"
|
||||||
|
},
|
||||||
|
"exports": {
|
||||||
|
".": "./mod.ts",
|
||||||
|
"./opencode": "./dist/opencode.js",
|
||||||
|
"./keep": "./dist/keep.js",
|
||||||
|
"./routes": "./dist/routes.js",
|
||||||
|
"./src/*": "./src/*",
|
||||||
|
"./agent/*": "./agent/*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
872
pnpm-lock.yaml
generated
872
pnpm-lock.yaml
generated
@@ -4,164 +4,930 @@ settings:
|
|||||||
autoInstallPeers: true
|
autoInstallPeers: true
|
||||||
excludeLinksFromLockfile: false
|
excludeLinksFromLockfile: false
|
||||||
|
|
||||||
|
overrides:
|
||||||
|
zod: ^4.3.6
|
||||||
|
|
||||||
importers:
|
importers:
|
||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@kevisual/query':
|
'@kevisual/query':
|
||||||
specifier: ^0.0.35
|
specifier: ^0.0.38
|
||||||
version: 0.0.35
|
version: 0.0.38
|
||||||
'@kevisual/router':
|
'@kevisual/router':
|
||||||
specifier: ^0.0.55
|
specifier: ^0.0.64
|
||||||
version: 0.0.55
|
version: 0.0.64(typescript@5.9.3)
|
||||||
'@kevisual/use-config':
|
'@kevisual/use-config':
|
||||||
specifier: ^1.0.28
|
specifier: ^1.0.28
|
||||||
version: 1.0.28(dotenv@17.2.3)
|
version: 1.0.28(dotenv@17.2.3)
|
||||||
es-toolkit:
|
es-toolkit:
|
||||||
specifier: ^1.43.0
|
specifier: ^1.44.0
|
||||||
version: 1.43.0
|
version: 1.44.0
|
||||||
nanoid:
|
nanoid:
|
||||||
specifier: ^5.1.6
|
specifier: ^5.1.6
|
||||||
version: 5.1.6
|
version: 5.1.6
|
||||||
|
unstorage:
|
||||||
|
specifier: ^1.17.4
|
||||||
|
version: 1.17.4
|
||||||
|
ws:
|
||||||
|
specifier: npm:@kevisual/ws
|
||||||
|
version: '@kevisual/ws@8.19.0'
|
||||||
zod:
|
zod:
|
||||||
specifier: ^4.3.5
|
specifier: ^4.3.6
|
||||||
version: 4.3.5
|
version: 4.3.6
|
||||||
devDependencies:
|
devDependencies:
|
||||||
|
'@kevisual/ai':
|
||||||
|
specifier: ^0.0.24
|
||||||
|
version: 0.0.24
|
||||||
'@kevisual/context':
|
'@kevisual/context':
|
||||||
specifier: ^0.0.4
|
specifier: ^0.0.4
|
||||||
version: 0.0.4
|
version: 0.0.4
|
||||||
'@kevisual/types':
|
'@kevisual/types':
|
||||||
specifier: ^0.0.11
|
specifier: ^0.0.12
|
||||||
version: 0.0.11
|
version: 0.0.12
|
||||||
'@opencode-ai/plugin':
|
'@opencode-ai/plugin':
|
||||||
specifier: ^1.1.23
|
specifier: ^1.1.44
|
||||||
version: 1.1.23
|
version: 1.1.44
|
||||||
'@types/bun':
|
'@types/bun':
|
||||||
specifier: ^1.3.6
|
specifier: ^1.3.8
|
||||||
version: 1.3.6
|
version: 1.3.8
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^25.0.9
|
specifier: ^25.1.0
|
||||||
version: 25.0.9
|
version: 25.1.0
|
||||||
|
'@types/ws':
|
||||||
|
specifier: ^8.18.1
|
||||||
|
version: 8.18.1
|
||||||
|
dayjs:
|
||||||
|
specifier: ^1.11.19
|
||||||
|
version: 1.11.19
|
||||||
dotenv:
|
dotenv:
|
||||||
specifier: ^17.2.3
|
specifier: ^17.2.3
|
||||||
version: 17.2.3
|
version: 17.2.3
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
|
'@babel/code-frame@7.28.6':
|
||||||
|
resolution: {integrity: sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
|
'@babel/helper-validator-identifier@7.28.5':
|
||||||
|
resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
|
'@jridgewell/sourcemap-codec@1.5.5':
|
||||||
|
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
|
||||||
|
|
||||||
|
'@kevisual/ai@0.0.24':
|
||||||
|
resolution: {integrity: sha512-7jvZk1/L//VIClK7usuNgN4ZA9Etgbooka1Sj5quE/0UywR+NNnwqXVZ89Y1fBhI1TkhauDsdJBAtcQ7r/vbVw==}
|
||||||
|
|
||||||
'@kevisual/context@0.0.4':
|
'@kevisual/context@0.0.4':
|
||||||
resolution: {integrity: sha512-HJeLeZQLU+7tCluSfOyvkgKLs0HjCZrdJlZgEgKRSa8XTwZfMAUt6J7qZTbrZAHBlPtX68EPu/PI8JMCeu3WAQ==}
|
resolution: {integrity: sha512-HJeLeZQLU+7tCluSfOyvkgKLs0HjCZrdJlZgEgKRSa8XTwZfMAUt6J7qZTbrZAHBlPtX68EPu/PI8JMCeu3WAQ==}
|
||||||
|
|
||||||
|
'@kevisual/dts@0.0.3':
|
||||||
|
resolution: {integrity: sha512-4T/m2LqhtwWEW+lWmg7jLxKFW7VtIAftsWFDDZvh10bZunqFf8iXxChHcVSQWikghJb4cq1IkWzPkvc2l+Asdw==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
'@kevisual/load@0.0.6':
|
'@kevisual/load@0.0.6':
|
||||||
resolution: {integrity: sha512-+3YTFehRcZ1haGel5DKYMUwmi5i6f2psyaPZlfkKU/cOXgkpwoG9/BEqPCnPjicKqqnksEpixVRkyHJ+5bjLVA==}
|
resolution: {integrity: sha512-+3YTFehRcZ1haGel5DKYMUwmi5i6f2psyaPZlfkKU/cOXgkpwoG9/BEqPCnPjicKqqnksEpixVRkyHJ+5bjLVA==}
|
||||||
|
|
||||||
'@kevisual/query@0.0.35':
|
'@kevisual/logger@0.0.4':
|
||||||
resolution: {integrity: sha512-80dyy2LMCmEC72g+X4QWUKlZErhawQPgnGSBNR4yhrBcFgHIJQ14LR1Z+bS5S1I7db+1PDNpaxBTjIaoYoXunw==}
|
resolution: {integrity: sha512-+fpr92eokSxoGOW1SIRl/27lPuO+zyY+feR5o2Q4YCNlAdt2x64NwC/w8r/3NEC5QenLgd4K0azyKTI2mHbARw==}
|
||||||
|
|
||||||
'@kevisual/router@0.0.55':
|
'@kevisual/permission@0.0.3':
|
||||||
resolution: {integrity: sha512-DVhXbbUCfSWWXsp1id1HBrkGiMZ6nFUBD1/C5E7IpLE5B32w7sv2xjKUt98OriFl0uyuneMEIZuZsAQaKplQ5g==}
|
resolution: {integrity: sha512-8JsA/5O5Ax/z+M+MYpFYdlioHE6jNmWMuFSokBWYs9CCAHNiSKMR01YLkoVDoPvncfH/Y8F5K/IEXRCbptuMNA==}
|
||||||
|
|
||||||
'@kevisual/types@0.0.11':
|
'@kevisual/query@0.0.38':
|
||||||
resolution: {integrity: sha512-idNLDTEKVdNXZHFQq8PTN62nflh94kvGtx+v8YDcMxt0Zo+HWVZTFElm+dMQxAs/vn4wo8F2r3VwzWNX/vcqwQ==}
|
resolution: {integrity: sha512-bfvbSodsZyMfwY+1T2SvDeOCKsT/AaIxlVe0+B1R/fNhlg2MDq2CP0L9HKiFkEm+OXrvXcYDMKPUituVUM5J6Q==}
|
||||||
|
|
||||||
|
'@kevisual/router@0.0.64':
|
||||||
|
resolution: {integrity: sha512-EYz1MZxrltgySUL0Y+/MtZf2FEmqC5U8GmFAqvHNjgtS5FJdHpxRjo6zab4+0wSUlVyCxCpZXFY5vHB/g+nQBw==}
|
||||||
|
|
||||||
|
'@kevisual/types@0.0.12':
|
||||||
|
resolution: {integrity: sha512-zJXH2dosir3jVrQ6QG4i0+iLQeT9gJ3H+cKXs8ReWboxBSYzUZO78XssVeVrFPsJ33iaAqo4q3DWbSS1dWGn7Q==}
|
||||||
|
|
||||||
'@kevisual/use-config@1.0.28':
|
'@kevisual/use-config@1.0.28':
|
||||||
resolution: {integrity: sha512-ngF+LDbjxpXWrZNmnShIKF/jPpAa+ezV+DcgoZIIzHlRnIjE+rr9sLkN/B7WJbiH9C/j1tQXOILY8ujBqILrow==}
|
resolution: {integrity: sha512-ngF+LDbjxpXWrZNmnShIKF/jPpAa+ezV+DcgoZIIzHlRnIjE+rr9sLkN/B7WJbiH9C/j1tQXOILY8ujBqILrow==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
dotenv: ^17
|
dotenv: ^17
|
||||||
|
|
||||||
'@opencode-ai/plugin@1.1.23':
|
'@kevisual/ws@8.19.0':
|
||||||
resolution: {integrity: sha512-O/iLSKOUuzD95UWhj9y/tEuycPEBv36de0suHXXqeYLWZLZ16DAUSKR+YG7rvRjJS0sbn4biVMw+k7XXk/oxiQ==}
|
resolution: {integrity: sha512-jLsL80wBBKkrJZrfk3SQpJ9JA/zREdlUROj7eCkmzqduAWKSI0wVcXuCKf+mLFCHB0Q0Tkh2rgzjSlurt3JQgw==}
|
||||||
|
engines: {node: '>=10.0.0'}
|
||||||
|
|
||||||
'@opencode-ai/sdk@1.1.23':
|
'@opencode-ai/plugin@1.1.44':
|
||||||
resolution: {integrity: sha512-YjN9ogzkLol92s+/iARXRop9/5oFIezUkvWVay12u1IM6A/WJs50DeKl3oL0x4a68P1a5tI5gD98dLnk2+AlsA==}
|
resolution: {integrity: sha512-5w66Dq2Fugwgr2yrd8obvnlIEjBOuya82UgfR/3z3EzlyNDi2sitQSYbz7CcOtwd89eZ0n/tH/JX2KDGVuzxTQ==}
|
||||||
|
|
||||||
'@types/bun@1.3.6':
|
'@opencode-ai/sdk@1.1.44':
|
||||||
resolution: {integrity: sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA==}
|
resolution: {integrity: sha512-coQgtSSCbY46/GY+M5zG0rChiLSJWSjPERRt5L1hbjvDWvErelVV0ILPbd1+3CwJLFTedBYgotby2TcO8U0IfQ==}
|
||||||
|
|
||||||
'@types/node@25.0.9':
|
'@rollup/plugin-commonjs@28.0.9':
|
||||||
resolution: {integrity: sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw==}
|
resolution: {integrity: sha512-PIR4/OHZ79romx0BVVll/PkwWpJ7e5lsqFa3gFfcrFPWwLXLV39JVUzQV9RKjWerE7B845Hqjj9VYlQeieZ2dA==}
|
||||||
|
engines: {node: '>=16.0.0 || 14 >= 14.17'}
|
||||||
|
peerDependencies:
|
||||||
|
rollup: ^2.68.0||^3.0.0||^4.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
rollup:
|
||||||
|
optional: true
|
||||||
|
|
||||||
bun-types@1.3.6:
|
'@rollup/plugin-node-resolve@16.0.3':
|
||||||
resolution: {integrity: sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ==}
|
resolution: {integrity: sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
rollup: ^2.78.0||^3.0.0||^4.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
rollup:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/plugin-typescript@12.3.0':
|
||||||
|
resolution: {integrity: sha512-7DP0/p7y3t67+NabT9f8oTBFE6gGkto4SA6Np2oudYmZE/m1dt8RB0SjL1msMxFpLo631qjRCcBlAbq1ml/Big==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
rollup: ^2.14.0||^3.0.0||^4.0.0
|
||||||
|
tslib: '*'
|
||||||
|
typescript: '>=3.7.0'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
rollup:
|
||||||
|
optional: true
|
||||||
|
tslib:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/pluginutils@5.3.0':
|
||||||
|
resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
rollup:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-android-arm-eabi@4.57.0':
|
||||||
|
resolution: {integrity: sha512-tPgXB6cDTndIe1ah7u6amCI1T0SsnlOuKgg10Xh3uizJk4e5M1JGaUMk7J4ciuAUcFpbOiNhm2XIjP9ON0dUqA==}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@rollup/rollup-android-arm64@4.57.0':
|
||||||
|
resolution: {integrity: sha512-sa4LyseLLXr1onr97StkU1Nb7fWcg6niokTwEVNOO7awaKaoRObQ54+V/hrF/BP1noMEaaAW6Fg2d/CfLiq3Mg==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@rollup/rollup-darwin-arm64@4.57.0':
|
||||||
|
resolution: {integrity: sha512-/NNIj9A7yLjKdmkx5dC2XQ9DmjIECpGpwHoGmA5E1AhU0fuICSqSWScPhN1yLCkEdkCwJIDu2xIeLPs60MNIVg==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@rollup/rollup-darwin-x64@4.57.0':
|
||||||
|
resolution: {integrity: sha512-xoh8abqgPrPYPr7pTYipqnUi1V3em56JzE/HgDgitTqZBZ3yKCWI+7KUkceM6tNweyUKYru1UMi7FC060RyKwA==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@rollup/rollup-freebsd-arm64@4.57.0':
|
||||||
|
resolution: {integrity: sha512-PCkMh7fNahWSbA0OTUQ2OpYHpjZZr0hPr8lId8twD7a7SeWrvT3xJVyza+dQwXSSq4yEQTMoXgNOfMCsn8584g==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@rollup/rollup-freebsd-x64@4.57.0':
|
||||||
|
resolution: {integrity: sha512-1j3stGx+qbhXql4OCDZhnK7b01s6rBKNybfsX+TNrEe9JNq4DLi1yGiR1xW+nL+FNVvI4D02PUnl6gJ/2y6WJA==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm-gnueabihf@4.57.0':
|
||||||
|
resolution: {integrity: sha512-eyrr5W08Ms9uM0mLcKfM/Uzx7hjhz2bcjv8P2uynfj0yU8GGPdz8iYrBPhiLOZqahoAMB8ZiolRZPbbU2MAi6Q==}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm-musleabihf@4.57.0':
|
||||||
|
resolution: {integrity: sha512-Xds90ITXJCNyX9pDhqf85MKWUI4lqjiPAipJ8OLp8xqI2Ehk+TCVhF9rvOoN8xTbcafow3QOThkNnrM33uCFQA==}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm64-gnu@4.57.0':
|
||||||
|
resolution: {integrity: sha512-Xws2KA4CLvZmXjy46SQaXSejuKPhwVdaNinldoYfqruZBaJHqVo6hnRa8SDo9z7PBW5x84SH64+izmldCgbezw==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm64-musl@4.57.0':
|
||||||
|
resolution: {integrity: sha512-hrKXKbX5FdaRJj7lTMusmvKbhMJSGWJ+w++4KmjiDhpTgNlhYobMvKfDoIWecy4O60K6yA4SnztGuNTQF+Lplw==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-loong64-gnu@4.57.0':
|
||||||
|
resolution: {integrity: sha512-6A+nccfSDGKsPm00d3xKcrsBcbqzCTAukjwWK6rbuAnB2bHaL3r9720HBVZ/no7+FhZLz/U3GwwZZEh6tOSI8Q==}
|
||||||
|
cpu: [loong64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-loong64-musl@4.57.0':
|
||||||
|
resolution: {integrity: sha512-4P1VyYUe6XAJtQH1Hh99THxr0GKMMwIXsRNOceLrJnaHTDgk1FTcTimDgneRJPvB3LqDQxUmroBclQ1S0cIJwQ==}
|
||||||
|
cpu: [loong64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-ppc64-gnu@4.57.0':
|
||||||
|
resolution: {integrity: sha512-8Vv6pLuIZCMcgXre6c3nOPhE0gjz1+nZP6T+hwWjr7sVH8k0jRkH+XnfjjOTglyMBdSKBPPz54/y1gToSKwrSQ==}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-ppc64-musl@4.57.0':
|
||||||
|
resolution: {integrity: sha512-r1te1M0Sm2TBVD/RxBPC6RZVwNqUTwJTA7w+C/IW5v9Ssu6xmxWEi+iJQlpBhtUiT1raJ5b48pI8tBvEjEFnFA==}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-riscv64-gnu@4.57.0':
|
||||||
|
resolution: {integrity: sha512-say0uMU/RaPm3CDQLxUUTF2oNWL8ysvHkAjcCzV2znxBr23kFfaxocS9qJm+NdkRhF8wtdEEAJuYcLPhSPbjuQ==}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-riscv64-musl@4.57.0':
|
||||||
|
resolution: {integrity: sha512-/MU7/HizQGsnBREtRpcSbSV1zfkoxSTR7wLsRmBPQ8FwUj5sykrP1MyJTvsxP5KBq9SyE6kH8UQQQwa0ASeoQQ==}
|
||||||
|
cpu: [riscv64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-s390x-gnu@4.57.0':
|
||||||
|
resolution: {integrity: sha512-Q9eh+gUGILIHEaJf66aF6a414jQbDnn29zeu0eX3dHMuysnhTvsUvZTCAyZ6tJhUjnvzBKE4FtuaYxutxRZpOg==}
|
||||||
|
cpu: [s390x]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-x64-gnu@4.57.0':
|
||||||
|
resolution: {integrity: sha512-OR5p5yG5OKSxHReWmwvM0P+VTPMwoBS45PXTMYaskKQqybkS3Kmugq1W+YbNWArF8/s7jQScgzXUhArzEQ7x0A==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-x64-musl@4.57.0':
|
||||||
|
resolution: {integrity: sha512-XeatKzo4lHDsVEbm1XDHZlhYZZSQYym6dg2X/Ko0kSFgio+KXLsxwJQprnR48GvdIKDOpqWqssC3iBCjoMcMpw==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@rollup/rollup-openbsd-x64@4.57.0':
|
||||||
|
resolution: {integrity: sha512-Lu71y78F5qOfYmubYLHPcJm74GZLU6UJ4THkf/a1K7Tz2ycwC2VUbsqbJAXaR6Bx70SRdlVrt2+n5l7F0agTUw==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [openbsd]
|
||||||
|
|
||||||
|
'@rollup/rollup-openharmony-arm64@4.57.0':
|
||||||
|
resolution: {integrity: sha512-v5xwKDWcu7qhAEcsUubiav7r+48Uk/ENWdr82MBZZRIm7zThSxCIVDfb3ZeRRq9yqk+oIzMdDo6fCcA5DHfMyA==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [openharmony]
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-arm64-msvc@4.57.0':
|
||||||
|
resolution: {integrity: sha512-XnaaaSMGSI6Wk8F4KK3QP7GfuuhjGchElsVerCplUuxRIzdvZ7hRBpLR0omCmw+kI2RFJB80nenhOoGXlJ5TfQ==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-ia32-msvc@4.57.0':
|
||||||
|
resolution: {integrity: sha512-3K1lP+3BXY4t4VihLw5MEg6IZD3ojSYzqzBG571W3kNQe4G4CcFpSUQVgurYgib5d+YaCjeFow8QivWp8vuSvA==}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-x64-gnu@4.57.0':
|
||||||
|
resolution: {integrity: sha512-MDk610P/vJGc5L5ImE4k5s+GZT3en0KoK1MKPXCRgzmksAMk79j4h3k1IerxTNqwDLxsGxStEZVBqG0gIqZqoA==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-x64-msvc@4.57.0':
|
||||||
|
resolution: {integrity: sha512-Zv7v6q6aV+VslnpwzqKAmrk5JdVkLUzok2208ZXGipjb+msxBr/fJPZyeEXiFgH7k62Ak0SLIfxQRZQvTuf7rQ==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@types/bun@1.3.8':
|
||||||
|
resolution: {integrity: sha512-3LvWJ2q5GerAXYxO2mffLTqOzEu5qnhEAlh48Vnu8WQfnmSwbgagjGZV6BoHKJztENYEDn6QmVd949W4uESRJA==}
|
||||||
|
|
||||||
|
'@types/estree@1.0.8':
|
||||||
|
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
||||||
|
|
||||||
|
'@types/node@25.1.0':
|
||||||
|
resolution: {integrity: sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA==}
|
||||||
|
|
||||||
|
'@types/resolve@1.20.2':
|
||||||
|
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
|
||||||
|
|
||||||
|
'@types/ws@8.18.1':
|
||||||
|
resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
|
||||||
|
|
||||||
|
anymatch@3.1.3:
|
||||||
|
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
|
||||||
|
engines: {node: '>= 8'}
|
||||||
|
|
||||||
|
bun-types@1.3.8:
|
||||||
|
resolution: {integrity: sha512-fL99nxdOWvV4LqjmC+8Q9kW3M4QTtTR1eePs94v5ctGqU8OeceWrSUaRw3JYb7tU3FkMIAjkueehrHPPPGKi5Q==}
|
||||||
|
|
||||||
|
chokidar@5.0.0:
|
||||||
|
resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==}
|
||||||
|
engines: {node: '>= 20.19.0'}
|
||||||
|
|
||||||
|
commondir@1.0.1:
|
||||||
|
resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==}
|
||||||
|
|
||||||
|
cookie-es@1.2.2:
|
||||||
|
resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==}
|
||||||
|
|
||||||
|
crossws@0.3.5:
|
||||||
|
resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==}
|
||||||
|
|
||||||
|
dayjs@1.11.19:
|
||||||
|
resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==}
|
||||||
|
|
||||||
|
deepmerge@4.3.1:
|
||||||
|
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
defu@6.1.4:
|
||||||
|
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
|
||||||
|
|
||||||
|
destr@2.0.5:
|
||||||
|
resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==}
|
||||||
|
|
||||||
dotenv@17.2.3:
|
dotenv@17.2.3:
|
||||||
resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==}
|
resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
es-toolkit@1.43.0:
|
es-toolkit@1.44.0:
|
||||||
resolution: {integrity: sha512-SKCT8AsWvYzBBuUqMk4NPwFlSdqLpJwmy6AP322ERn8W2YLIB6JBXnwMI2Qsh2gfphT3q7EKAxKb23cvFHFwKA==}
|
resolution: {integrity: sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg==}
|
||||||
|
|
||||||
|
estree-walker@2.0.2:
|
||||||
|
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
|
||||||
|
|
||||||
eventemitter3@5.0.1:
|
eventemitter3@5.0.1:
|
||||||
resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
|
resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
|
||||||
|
|
||||||
|
fdir@6.5.0:
|
||||||
|
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
|
||||||
|
engines: {node: '>=12.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
picomatch: ^3 || ^4
|
||||||
|
peerDependenciesMeta:
|
||||||
|
picomatch:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
fsevents@2.3.3:
|
||||||
|
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||||
|
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
function-bind@1.1.2:
|
||||||
|
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
|
||||||
|
|
||||||
|
h3@1.15.5:
|
||||||
|
resolution: {integrity: sha512-xEyq3rSl+dhGX2Lm0+eFQIAzlDN6Fs0EcC4f7BNUmzaRX/PTzeuM+Tr2lHB8FoXggsQIeXLj8EDVgs5ywxyxmg==}
|
||||||
|
|
||||||
|
hasown@2.0.2:
|
||||||
|
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
hono@4.11.7:
|
||||||
|
resolution: {integrity: sha512-l7qMiNee7t82bH3SeyUCt9UF15EVmaBvsppY2zQtrbIhl/yzBTny+YUxsVjSjQ6gaqaeVtZmGocom8TzBlA4Yw==}
|
||||||
|
engines: {node: '>=16.9.0'}
|
||||||
|
|
||||||
|
iron-webcrypto@1.2.1:
|
||||||
|
resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==}
|
||||||
|
|
||||||
|
is-core-module@2.16.1:
|
||||||
|
resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
is-module@1.0.0:
|
||||||
|
resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
|
||||||
|
|
||||||
|
is-reference@1.2.1:
|
||||||
|
resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==}
|
||||||
|
|
||||||
|
js-tokens@4.0.0:
|
||||||
|
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
||||||
|
|
||||||
|
lru-cache@11.2.5:
|
||||||
|
resolution: {integrity: sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==}
|
||||||
|
engines: {node: 20 || >=22}
|
||||||
|
|
||||||
|
magic-string@0.30.21:
|
||||||
|
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
|
||||||
|
|
||||||
nanoid@5.1.6:
|
nanoid@5.1.6:
|
||||||
resolution: {integrity: sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==}
|
resolution: {integrity: sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==}
|
||||||
engines: {node: ^18 || >=20}
|
engines: {node: ^18 || >=20}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
node-fetch-native@1.6.7:
|
||||||
|
resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==}
|
||||||
|
|
||||||
|
node-mock-http@1.0.4:
|
||||||
|
resolution: {integrity: sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==}
|
||||||
|
|
||||||
|
normalize-path@3.0.0:
|
||||||
|
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
ofetch@1.5.1:
|
||||||
|
resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==}
|
||||||
|
|
||||||
|
path-parse@1.0.7:
|
||||||
|
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
|
||||||
|
|
||||||
|
picocolors@1.1.1:
|
||||||
|
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
||||||
|
|
||||||
|
picomatch@2.3.1:
|
||||||
|
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
|
||||||
|
engines: {node: '>=8.6'}
|
||||||
|
|
||||||
|
picomatch@4.0.3:
|
||||||
|
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
radix3@1.1.2:
|
||||||
|
resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==}
|
||||||
|
|
||||||
|
readdirp@5.0.0:
|
||||||
|
resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==}
|
||||||
|
engines: {node: '>= 20.19.0'}
|
||||||
|
|
||||||
|
resolve@1.22.11:
|
||||||
|
resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
rollup-plugin-dts@6.3.0:
|
||||||
|
resolution: {integrity: sha512-d0UrqxYd8KyZ6i3M2Nx7WOMy708qsV/7fTHMHxCMCBOAe3V/U7OMPu5GkX8hC+cmkHhzGnfeYongl1IgiooddA==}
|
||||||
|
engines: {node: '>=16'}
|
||||||
|
peerDependencies:
|
||||||
|
rollup: ^3.29.4 || ^4
|
||||||
|
typescript: ^4.5 || ^5.0
|
||||||
|
|
||||||
|
rollup@4.57.0:
|
||||||
|
resolution: {integrity: sha512-e5lPJi/aui4TO1LpAXIRLySmwXSE8k3b9zoGfd42p67wzxog4WHjiZF3M2uheQih4DGyc25QEV4yRBbpueNiUA==}
|
||||||
|
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
supports-preserve-symlinks-flag@1.0.0:
|
||||||
|
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
tslib@2.8.1:
|
tslib@2.8.1:
|
||||||
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
||||||
|
|
||||||
|
typescript@5.9.3:
|
||||||
|
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
|
||||||
|
engines: {node: '>=14.17'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
ufo@1.6.3:
|
||||||
|
resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==}
|
||||||
|
|
||||||
|
uncrypto@0.1.3:
|
||||||
|
resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==}
|
||||||
|
|
||||||
undici-types@7.16.0:
|
undici-types@7.16.0:
|
||||||
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
|
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
|
||||||
|
|
||||||
zod@4.1.8:
|
unstorage@1.17.4:
|
||||||
resolution: {integrity: sha512-5R1P+WwQqmmMIEACyzSvo4JXHY5WiAFHRMg+zBZKgKS+Q1viRa0C1hmUKtHltoIFKtIdki3pRxkmpP74jnNYHQ==}
|
resolution: {integrity: sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw==}
|
||||||
|
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
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@azure/app-configuration':
|
||||||
|
optional: true
|
||||||
|
'@azure/cosmos':
|
||||||
|
optional: true
|
||||||
|
'@azure/data-tables':
|
||||||
|
optional: true
|
||||||
|
'@azure/identity':
|
||||||
|
optional: true
|
||||||
|
'@azure/keyvault-secrets':
|
||||||
|
optional: true
|
||||||
|
'@azure/storage-blob':
|
||||||
|
optional: true
|
||||||
|
'@capacitor/preferences':
|
||||||
|
optional: true
|
||||||
|
'@deno/kv':
|
||||||
|
optional: true
|
||||||
|
'@netlify/blobs':
|
||||||
|
optional: true
|
||||||
|
'@planetscale/database':
|
||||||
|
optional: true
|
||||||
|
'@upstash/redis':
|
||||||
|
optional: true
|
||||||
|
'@vercel/blob':
|
||||||
|
optional: true
|
||||||
|
'@vercel/functions':
|
||||||
|
optional: true
|
||||||
|
'@vercel/kv':
|
||||||
|
optional: true
|
||||||
|
aws4fetch:
|
||||||
|
optional: true
|
||||||
|
db0:
|
||||||
|
optional: true
|
||||||
|
idb-keyval:
|
||||||
|
optional: true
|
||||||
|
ioredis:
|
||||||
|
optional: true
|
||||||
|
uploadthing:
|
||||||
|
optional: true
|
||||||
|
|
||||||
zod@4.3.5:
|
zod@4.3.6:
|
||||||
resolution: {integrity: sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==}
|
resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
|
||||||
|
|
||||||
snapshots:
|
snapshots:
|
||||||
|
|
||||||
|
'@babel/code-frame@7.28.6':
|
||||||
|
dependencies:
|
||||||
|
'@babel/helper-validator-identifier': 7.28.5
|
||||||
|
js-tokens: 4.0.0
|
||||||
|
picocolors: 1.1.1
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@babel/helper-validator-identifier@7.28.5':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@jridgewell/sourcemap-codec@1.5.5': {}
|
||||||
|
|
||||||
|
'@kevisual/ai@0.0.24':
|
||||||
|
dependencies:
|
||||||
|
'@kevisual/logger': 0.0.4
|
||||||
|
'@kevisual/permission': 0.0.3
|
||||||
|
'@kevisual/query': 0.0.38
|
||||||
|
|
||||||
'@kevisual/context@0.0.4': {}
|
'@kevisual/context@0.0.4': {}
|
||||||
|
|
||||||
|
'@kevisual/dts@0.0.3(typescript@5.9.3)':
|
||||||
|
dependencies:
|
||||||
|
'@rollup/plugin-commonjs': 28.0.9(rollup@4.57.0)
|
||||||
|
'@rollup/plugin-node-resolve': 16.0.3(rollup@4.57.0)
|
||||||
|
'@rollup/plugin-typescript': 12.3.0(rollup@4.57.0)(tslib@2.8.1)(typescript@5.9.3)
|
||||||
|
rollup: 4.57.0
|
||||||
|
rollup-plugin-dts: 6.3.0(rollup@4.57.0)(typescript@5.9.3)
|
||||||
|
tslib: 2.8.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- typescript
|
||||||
|
|
||||||
'@kevisual/load@0.0.6':
|
'@kevisual/load@0.0.6':
|
||||||
dependencies:
|
dependencies:
|
||||||
eventemitter3: 5.0.1
|
eventemitter3: 5.0.1
|
||||||
|
|
||||||
'@kevisual/query@0.0.35':
|
'@kevisual/logger@0.0.4': {}
|
||||||
|
|
||||||
|
'@kevisual/permission@0.0.3': {}
|
||||||
|
|
||||||
|
'@kevisual/query@0.0.38':
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
|
|
||||||
'@kevisual/router@0.0.55': {}
|
'@kevisual/router@0.0.64(typescript@5.9.3)':
|
||||||
|
dependencies:
|
||||||
|
'@kevisual/dts': 0.0.3(typescript@5.9.3)
|
||||||
|
hono: 4.11.7
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- typescript
|
||||||
|
|
||||||
'@kevisual/types@0.0.11': {}
|
'@kevisual/types@0.0.12': {}
|
||||||
|
|
||||||
'@kevisual/use-config@1.0.28(dotenv@17.2.3)':
|
'@kevisual/use-config@1.0.28(dotenv@17.2.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@kevisual/load': 0.0.6
|
'@kevisual/load': 0.0.6
|
||||||
dotenv: 17.2.3
|
dotenv: 17.2.3
|
||||||
|
|
||||||
'@opencode-ai/plugin@1.1.23':
|
'@kevisual/ws@8.19.0': {}
|
||||||
|
|
||||||
|
'@opencode-ai/plugin@1.1.44':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@opencode-ai/sdk': 1.1.23
|
'@opencode-ai/sdk': 1.1.44
|
||||||
zod: 4.1.8
|
zod: 4.3.6
|
||||||
|
|
||||||
'@opencode-ai/sdk@1.1.23': {}
|
'@opencode-ai/sdk@1.1.44': {}
|
||||||
|
|
||||||
'@types/bun@1.3.6':
|
'@rollup/plugin-commonjs@28.0.9(rollup@4.57.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
bun-types: 1.3.6
|
'@rollup/pluginutils': 5.3.0(rollup@4.57.0)
|
||||||
|
commondir: 1.0.1
|
||||||
|
estree-walker: 2.0.2
|
||||||
|
fdir: 6.5.0(picomatch@4.0.3)
|
||||||
|
is-reference: 1.2.1
|
||||||
|
magic-string: 0.30.21
|
||||||
|
picomatch: 4.0.3
|
||||||
|
optionalDependencies:
|
||||||
|
rollup: 4.57.0
|
||||||
|
|
||||||
'@types/node@25.0.9':
|
'@rollup/plugin-node-resolve@16.0.3(rollup@4.57.0)':
|
||||||
|
dependencies:
|
||||||
|
'@rollup/pluginutils': 5.3.0(rollup@4.57.0)
|
||||||
|
'@types/resolve': 1.20.2
|
||||||
|
deepmerge: 4.3.1
|
||||||
|
is-module: 1.0.0
|
||||||
|
resolve: 1.22.11
|
||||||
|
optionalDependencies:
|
||||||
|
rollup: 4.57.0
|
||||||
|
|
||||||
|
'@rollup/plugin-typescript@12.3.0(rollup@4.57.0)(tslib@2.8.1)(typescript@5.9.3)':
|
||||||
|
dependencies:
|
||||||
|
'@rollup/pluginutils': 5.3.0(rollup@4.57.0)
|
||||||
|
resolve: 1.22.11
|
||||||
|
typescript: 5.9.3
|
||||||
|
optionalDependencies:
|
||||||
|
rollup: 4.57.0
|
||||||
|
tslib: 2.8.1
|
||||||
|
|
||||||
|
'@rollup/pluginutils@5.3.0(rollup@4.57.0)':
|
||||||
|
dependencies:
|
||||||
|
'@types/estree': 1.0.8
|
||||||
|
estree-walker: 2.0.2
|
||||||
|
picomatch: 4.0.3
|
||||||
|
optionalDependencies:
|
||||||
|
rollup: 4.57.0
|
||||||
|
|
||||||
|
'@rollup/rollup-android-arm-eabi@4.57.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-android-arm64@4.57.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-darwin-arm64@4.57.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-darwin-x64@4.57.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-freebsd-arm64@4.57.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-freebsd-x64@4.57.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm-gnueabihf@4.57.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm-musleabihf@4.57.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm64-gnu@4.57.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-arm64-musl@4.57.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-loong64-gnu@4.57.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-loong64-musl@4.57.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-ppc64-gnu@4.57.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-ppc64-musl@4.57.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-riscv64-gnu@4.57.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-riscv64-musl@4.57.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-s390x-gnu@4.57.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-x64-gnu@4.57.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-linux-x64-musl@4.57.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-openbsd-x64@4.57.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-openharmony-arm64@4.57.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-arm64-msvc@4.57.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-ia32-msvc@4.57.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-x64-gnu@4.57.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@rollup/rollup-win32-x64-msvc@4.57.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@types/bun@1.3.8':
|
||||||
|
dependencies:
|
||||||
|
bun-types: 1.3.8
|
||||||
|
|
||||||
|
'@types/estree@1.0.8': {}
|
||||||
|
|
||||||
|
'@types/node@25.1.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 7.16.0
|
undici-types: 7.16.0
|
||||||
|
|
||||||
bun-types@1.3.6:
|
'@types/resolve@1.20.2': {}
|
||||||
|
|
||||||
|
'@types/ws@8.18.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 25.0.9
|
'@types/node': 25.1.0
|
||||||
|
|
||||||
|
anymatch@3.1.3:
|
||||||
|
dependencies:
|
||||||
|
normalize-path: 3.0.0
|
||||||
|
picomatch: 2.3.1
|
||||||
|
|
||||||
|
bun-types@1.3.8:
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 25.1.0
|
||||||
|
|
||||||
|
chokidar@5.0.0:
|
||||||
|
dependencies:
|
||||||
|
readdirp: 5.0.0
|
||||||
|
|
||||||
|
commondir@1.0.1: {}
|
||||||
|
|
||||||
|
cookie-es@1.2.2: {}
|
||||||
|
|
||||||
|
crossws@0.3.5:
|
||||||
|
dependencies:
|
||||||
|
uncrypto: 0.1.3
|
||||||
|
|
||||||
|
dayjs@1.11.19: {}
|
||||||
|
|
||||||
|
deepmerge@4.3.1: {}
|
||||||
|
|
||||||
|
defu@6.1.4: {}
|
||||||
|
|
||||||
|
destr@2.0.5: {}
|
||||||
|
|
||||||
dotenv@17.2.3: {}
|
dotenv@17.2.3: {}
|
||||||
|
|
||||||
es-toolkit@1.43.0: {}
|
es-toolkit@1.44.0: {}
|
||||||
|
|
||||||
|
estree-walker@2.0.2: {}
|
||||||
|
|
||||||
eventemitter3@5.0.1: {}
|
eventemitter3@5.0.1: {}
|
||||||
|
|
||||||
|
fdir@6.5.0(picomatch@4.0.3):
|
||||||
|
optionalDependencies:
|
||||||
|
picomatch: 4.0.3
|
||||||
|
|
||||||
|
fsevents@2.3.3:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
function-bind@1.1.2: {}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
hasown@2.0.2:
|
||||||
|
dependencies:
|
||||||
|
function-bind: 1.1.2
|
||||||
|
|
||||||
|
hono@4.11.7: {}
|
||||||
|
|
||||||
|
iron-webcrypto@1.2.1: {}
|
||||||
|
|
||||||
|
is-core-module@2.16.1:
|
||||||
|
dependencies:
|
||||||
|
hasown: 2.0.2
|
||||||
|
|
||||||
|
is-module@1.0.0: {}
|
||||||
|
|
||||||
|
is-reference@1.2.1:
|
||||||
|
dependencies:
|
||||||
|
'@types/estree': 1.0.8
|
||||||
|
|
||||||
|
js-tokens@4.0.0:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
lru-cache@11.2.5: {}
|
||||||
|
|
||||||
|
magic-string@0.30.21:
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
|
|
||||||
nanoid@5.1.6: {}
|
nanoid@5.1.6: {}
|
||||||
|
|
||||||
|
node-fetch-native@1.6.7: {}
|
||||||
|
|
||||||
|
node-mock-http@1.0.4: {}
|
||||||
|
|
||||||
|
normalize-path@3.0.0: {}
|
||||||
|
|
||||||
|
ofetch@1.5.1:
|
||||||
|
dependencies:
|
||||||
|
destr: 2.0.5
|
||||||
|
node-fetch-native: 1.6.7
|
||||||
|
ufo: 1.6.3
|
||||||
|
|
||||||
|
path-parse@1.0.7: {}
|
||||||
|
|
||||||
|
picocolors@1.1.1:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
picomatch@2.3.1: {}
|
||||||
|
|
||||||
|
picomatch@4.0.3: {}
|
||||||
|
|
||||||
|
radix3@1.1.2: {}
|
||||||
|
|
||||||
|
readdirp@5.0.0: {}
|
||||||
|
|
||||||
|
resolve@1.22.11:
|
||||||
|
dependencies:
|
||||||
|
is-core-module: 2.16.1
|
||||||
|
path-parse: 1.0.7
|
||||||
|
supports-preserve-symlinks-flag: 1.0.0
|
||||||
|
|
||||||
|
rollup-plugin-dts@6.3.0(rollup@4.57.0)(typescript@5.9.3):
|
||||||
|
dependencies:
|
||||||
|
magic-string: 0.30.21
|
||||||
|
rollup: 4.57.0
|
||||||
|
typescript: 5.9.3
|
||||||
|
optionalDependencies:
|
||||||
|
'@babel/code-frame': 7.28.6
|
||||||
|
|
||||||
|
rollup@4.57.0:
|
||||||
|
dependencies:
|
||||||
|
'@types/estree': 1.0.8
|
||||||
|
optionalDependencies:
|
||||||
|
'@rollup/rollup-android-arm-eabi': 4.57.0
|
||||||
|
'@rollup/rollup-android-arm64': 4.57.0
|
||||||
|
'@rollup/rollup-darwin-arm64': 4.57.0
|
||||||
|
'@rollup/rollup-darwin-x64': 4.57.0
|
||||||
|
'@rollup/rollup-freebsd-arm64': 4.57.0
|
||||||
|
'@rollup/rollup-freebsd-x64': 4.57.0
|
||||||
|
'@rollup/rollup-linux-arm-gnueabihf': 4.57.0
|
||||||
|
'@rollup/rollup-linux-arm-musleabihf': 4.57.0
|
||||||
|
'@rollup/rollup-linux-arm64-gnu': 4.57.0
|
||||||
|
'@rollup/rollup-linux-arm64-musl': 4.57.0
|
||||||
|
'@rollup/rollup-linux-loong64-gnu': 4.57.0
|
||||||
|
'@rollup/rollup-linux-loong64-musl': 4.57.0
|
||||||
|
'@rollup/rollup-linux-ppc64-gnu': 4.57.0
|
||||||
|
'@rollup/rollup-linux-ppc64-musl': 4.57.0
|
||||||
|
'@rollup/rollup-linux-riscv64-gnu': 4.57.0
|
||||||
|
'@rollup/rollup-linux-riscv64-musl': 4.57.0
|
||||||
|
'@rollup/rollup-linux-s390x-gnu': 4.57.0
|
||||||
|
'@rollup/rollup-linux-x64-gnu': 4.57.0
|
||||||
|
'@rollup/rollup-linux-x64-musl': 4.57.0
|
||||||
|
'@rollup/rollup-openbsd-x64': 4.57.0
|
||||||
|
'@rollup/rollup-openharmony-arm64': 4.57.0
|
||||||
|
'@rollup/rollup-win32-arm64-msvc': 4.57.0
|
||||||
|
'@rollup/rollup-win32-ia32-msvc': 4.57.0
|
||||||
|
'@rollup/rollup-win32-x64-gnu': 4.57.0
|
||||||
|
'@rollup/rollup-win32-x64-msvc': 4.57.0
|
||||||
|
fsevents: 2.3.3
|
||||||
|
|
||||||
|
supports-preserve-symlinks-flag@1.0.0: {}
|
||||||
|
|
||||||
tslib@2.8.1: {}
|
tslib@2.8.1: {}
|
||||||
|
|
||||||
|
typescript@5.9.3: {}
|
||||||
|
|
||||||
|
ufo@1.6.3: {}
|
||||||
|
|
||||||
|
uncrypto@0.1.3: {}
|
||||||
|
|
||||||
undici-types@7.16.0: {}
|
undici-types@7.16.0: {}
|
||||||
|
|
||||||
zod@4.1.8: {}
|
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.5
|
||||||
|
node-fetch-native: 1.6.7
|
||||||
|
ofetch: 1.5.1
|
||||||
|
ufo: 1.6.3
|
||||||
|
|
||||||
zod@4.3.5: {}
|
zod@4.3.6: {}
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
对/agents 下的代码进行修改
|
|
||||||
|
|
||||||
需求1:
|
|
||||||
|
|
||||||
创建仓库, 需要仓库名字
|
|
||||||
1. 自动添加.cnb.yml, 对.cnb.yml的内容进行修改。修改TO_REPO对应的内容, TO_REPO,是“group+repo”需要传入仓库名字,默认group为kevisual
|
|
||||||
2. 自动添加opencode.json
|
|
||||||
|
|
||||||
需求2:
|
|
||||||
获取当前启动的云开发环境。
|
|
||||||
输出对应的请求的地址,token等信息
|
|
||||||
输出打开云开发的vscode,buddy,cursor,trae,qcoder等工具的地址
|
|
||||||
|
|
||||||
需求3:
|
|
||||||
|
|
||||||
|
|
||||||
@@ -7,41 +7,51 @@
|
|||||||
import { useKey } from "@kevisual/use-config"
|
import { useKey } from "@kevisual/use-config"
|
||||||
|
|
||||||
export const CNB_ENV = {
|
export const CNB_ENV = {
|
||||||
// 仓库相关配置
|
// 仓库相关配置
|
||||||
/** 仓库的 HTTPS 地址,如 "https://cnb.cool/kevisual/cnb" */
|
/** 仓库的 HTTPS 地址,如 "https://cnb.cool/kevisual/cnb" */
|
||||||
CNB_REPO_URL_HTTPS: useKey('CNB_REPO_URL_HTTPS'),
|
CNB_REPO_URL_HTTPS: useKey('CNB_REPO_URL_HTTPS'),
|
||||||
|
|
||||||
// 构建相关配置
|
// 构建相关配置
|
||||||
/** 流水线 ID,唯一标识一次构建流水线,如 "cnb-108-1jer5qekq-001" */
|
/** 流水线 ID,唯一标识一次构建流水线,如 "cnb-upo-1jfth1771-001" */
|
||||||
CNB_PIPELINE_ID: useKey('CNB_PIPELINE_ID'),
|
CNB_PIPELINE_ID: useKey('CNB_PIPELINE_ID'),
|
||||||
/** 构建 ID,与流水线 ID 相关联,如 "cnb-108-1jer5qekq" */
|
/** 构建 ID,与流水线 ID 相关联,如 "cnb-upo-1jfth1771" */
|
||||||
CNB_BUILD_ID: useKey('CNB_BUILD_ID'),
|
CNB_BUILD_ID: useKey('CNB_BUILD_ID'),
|
||||||
/** 构建开始时间,ISO 8601 格式,如 "2026-01-13T07:58:41.825Z" */
|
/** 构建开始时间,ISO 8601 格式,如 "2026-01-13T07:58:41.825Z" */
|
||||||
CNB_BUILD_START_TIME: useKey('CNB_BUILD_START_TIME'),
|
CNB_BUILD_START_TIME: useKey('CNB_BUILD_START_TIME'),
|
||||||
/** 构建日志 Web 界面 URL,用于在浏览器中查看构建日志 */
|
/** 构建日志 Web 界面 URL,用于在浏览器中查看构建日志 */
|
||||||
CNB_BUILD_WEB_URL: useKey('CNB_BUILD_WEB_URL'),
|
CNB_BUILD_WEB_URL: useKey('CNB_BUILD_WEB_URL'),
|
||||||
/** 触发构建的事件类型,如 "vscode" 表示由 VS Code 触发 */
|
/** 触发构建的事件类型,如 "vscode" 表示由 VS Code 触发 */
|
||||||
CNB_EVENT: useKey('CNB_EVENT'),
|
CNB_EVENT: useKey('CNB_EVENT'),
|
||||||
/** 当前构建对应的 Git 提交哈希值 */
|
/** 当前构建对应的 Git 提交哈希值 */
|
||||||
CNB_COMMIT: useKey('CNB_COMMIT'),
|
CNB_COMMIT: useKey('CNB_COMMIT'),
|
||||||
|
|
||||||
// VS Code 相关配置
|
// VS Code 相关配置
|
||||||
/** VS Code Web 界面的访问 URL,用于在浏览器中打开 VS Code */
|
/** VS Code Web 界面的访问 URL,用于在浏览器中打开 VS Code,例如:'https://cnb.cool/kevisual/cnb/-/workspace/vscode-web/cnb-upo-1jfth1771-001/'*/
|
||||||
CNB_VSCODE_WEB_URL: useKey('CNB_VSCODE_WEB_URL'),
|
CNB_VSCODE_WEB_URL: useKey('CNB_VSCODE_WEB_URL'),
|
||||||
/** VS Code 代理 URI,用于端口转发,{{port}} 会被替换为实际端口号, 例如: "https://1wnts22gq3-{{port}}.cnb.run"*/
|
/** VS Code 代理 URI,用于端口转发,{{port}} 会被替换为实际端口号, 例如: "https://1wnts22gq3-{{port}}.cnb.run"*/
|
||||||
CNB_VSCODE_PROXY_URI: useKey('CNB_VSCODE_PROXY_URI'),
|
CNB_VSCODE_PROXY_URI: useKey('CNB_VSCODE_PROXY_URI'),
|
||||||
|
/**
|
||||||
|
* VS Code Remote SSH 连接字符串,例如: vscode://vscode-remote/ssh-remote+cnb-upo-1jfth1771-001.8939f3d1-de13-486e-921f-f07943fcfa28-qng@cnb.space/workspace/"
|
||||||
|
* 是CNB_PIPELINE_ID和CNB_VSCODE_SSH_TOKEN的组合
|
||||||
|
*/
|
||||||
|
CNB_VSCODE_REMOTE_SSH_SCHEMA: useKey('CNB_VSCODE_REMOTE_SSH_SCHEMA'),
|
||||||
|
/**
|
||||||
|
* VS Code Remote SSH 连接的认证 Token 8939f3d1-de13-486e-921f-f07943fcfa28-qng
|
||||||
|
* 组装为ssh的链接字符串是 ssh CNB_PIPELINE_ID + '.' + CNB_VSCODE_SSH_TOKEN@cnb.space
|
||||||
|
*/
|
||||||
|
CNB_VSCODE_SSH_TOKEN: useKey('CNB_VSCODE_SSH_TOKEN'),
|
||||||
|
|
||||||
// 仓库标识配置
|
// 仓库标识配置
|
||||||
/** 仓库标识符,格式为 "组名/仓库名",如 "kevisual/cnb" */
|
/** 仓库标识符,格式为 "组名/仓库名",如 "kevisual/cnb" */
|
||||||
CNB_REPO_SLUG: useKey('CNB_REPO_SLUG'),
|
CNB_REPO_SLUG: useKey('CNB_REPO_SLUG'),
|
||||||
/** 组名/命名空间标识符,如 "kevisual" */
|
/** 组名/命名空间标识符,如 "kevisual" */
|
||||||
CNB_GROUP_SLUG: useKey('CNB_GROUP_SLUG'),
|
CNB_GROUP_SLUG: useKey('CNB_GROUP_SLUG'),
|
||||||
|
|
||||||
// 运行器资源配置
|
// 运行器资源配置
|
||||||
/** 运行器分配的 CPU 核心数,单位为核, 例如: "8"*/
|
/** 运行器分配的 CPU 核心数,单位为核, 例如: "8"*/
|
||||||
CNB_CPUS: useKey('CNB_CPUS'),
|
CNB_CPUS: useKey('CNB_CPUS'),
|
||||||
/** 运行器分配的内存大小,单位为 GB, 例如: "16"*/
|
/** 运行器分配的内存大小,单位为 GB, 例如: "16"*/
|
||||||
CNB_MEMORY: useKey('CNB_MEMORY'),
|
CNB_MEMORY: useKey('CNB_MEMORY'),
|
||||||
/** 运行器的 IP 地址,用于网络连接和调试 */
|
/** 运行器的 IP 地址,用于网络连接和调试 */
|
||||||
CNB_RUNNER_IP: useKey('CNB_RUNNER_IP'),
|
CNB_RUNNER_IP: useKey('CNB_RUNNER_IP'),
|
||||||
}
|
}
|
||||||
@@ -26,6 +26,7 @@ export type IssueItem = {
|
|||||||
author: IssueAuthor;
|
author: IssueAuthor;
|
||||||
labels: IssueLabel[];
|
labels: IssueLabel[];
|
||||||
|
|
||||||
|
body: string;
|
||||||
last_acted_at: string;
|
last_acted_at: string;
|
||||||
number: string;
|
number: string;
|
||||||
priority: string;
|
priority: string;
|
||||||
|
|||||||
1
src/keep.ts
Normal file
1
src/keep.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './workspace/keep-live.ts';
|
||||||
@@ -10,7 +10,7 @@ export class KnowledgeBase extends CNBCore {
|
|||||||
score_threshold?: number,
|
score_threshold?: number,
|
||||||
top_k?: number,
|
top_k?: number,
|
||||||
metadata_filtering_conditions?: MetadataFilteringConditions
|
metadata_filtering_conditions?: MetadataFilteringConditions
|
||||||
}): Promise<any> {
|
}): Promise<Result<QueryRag[]>> {
|
||||||
const url = `/${repo}/-/knowledge/base/query`;
|
const url = `/${repo}/-/knowledge/base/query`;
|
||||||
let postData = {
|
let postData = {
|
||||||
query: data.query,
|
query: data.query,
|
||||||
@@ -44,3 +44,16 @@ type MetadataFilteringConditions = {
|
|||||||
}>
|
}>
|
||||||
logical_operator?: 'adn' | 'or'
|
logical_operator?: 'adn' | 'or'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type QueryRag = {
|
||||||
|
chunk: string;
|
||||||
|
score: number;
|
||||||
|
metadata: {
|
||||||
|
hash: string;
|
||||||
|
name: string;
|
||||||
|
path: string;
|
||||||
|
position: string;
|
||||||
|
type: string; // code, text
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -54,7 +54,7 @@ export class Workspace extends CNBCore {
|
|||||||
return this.post({ url: '/workspace/delete', data });
|
return this.post({ url: '/workspace/delete', data });
|
||||||
}
|
}
|
||||||
/** 获取我的云原生开发环境列表 */
|
/** 获取我的云原生开发环境列表 */
|
||||||
async list(params?: ListParams): Promise<WorkspaceResult> {
|
async list(params?: ListParams): Promise<Result<WorkspaceResult>> {
|
||||||
return this.get({ url: '/workspace/list', params });
|
return this.get({ url: '/workspace/list', params });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
191
src/workspace/keep-live.ts
Normal file
191
src/workspace/keep-live.ts
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
// WebSocket Keep-Alive Client Library
|
||||||
|
import WebSocket from "ws";
|
||||||
|
|
||||||
|
export interface KeepAliveConfig {
|
||||||
|
wsUrl: string;
|
||||||
|
cookie: string;
|
||||||
|
reconnectInterval?: number;
|
||||||
|
maxReconnectAttempts?: number;
|
||||||
|
pingInterval?: number;
|
||||||
|
onMessage?: (data: Buffer | string) => void;
|
||||||
|
onConnect?: () => void;
|
||||||
|
onDisconnect?: (code: number) => void;
|
||||||
|
onError?: (error: Error) => void;
|
||||||
|
onSign?: (data: { type: string; data: string; signedData: string }) => void;
|
||||||
|
onExit?: (code?: number) => void;
|
||||||
|
debug?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ParsedMessage {
|
||||||
|
type: string;
|
||||||
|
raw: Buffer;
|
||||||
|
payload?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
type MessageHandler = (msg: ParsedMessage) => void;
|
||||||
|
|
||||||
|
export class WSKeepAlive {
|
||||||
|
private ws: WebSocket | null = null;
|
||||||
|
private config: Required<KeepAliveConfig>;
|
||||||
|
private reconnectAttempts = 0;
|
||||||
|
private pingTimer: NodeJS.Timeout | null = null;
|
||||||
|
private messageHandlers: Set<MessageHandler> = new Set();
|
||||||
|
private url: URL;
|
||||||
|
|
||||||
|
constructor(config: KeepAliveConfig) {
|
||||||
|
this.config = {
|
||||||
|
wsUrl: config.wsUrl,
|
||||||
|
cookie: config.cookie,
|
||||||
|
reconnectInterval: config.reconnectInterval ?? 5000,
|
||||||
|
maxReconnectAttempts: config.maxReconnectAttempts ?? 3,
|
||||||
|
pingInterval: config.pingInterval ?? 30000,
|
||||||
|
onMessage: config.onMessage ?? (() => { }),
|
||||||
|
onConnect: config.onConnect ?? (() => { }),
|
||||||
|
onDisconnect: config.onDisconnect ?? (() => { }),
|
||||||
|
onError: config.onError ?? (() => { }),
|
||||||
|
onSign: config.onSign ?? (() => { }),
|
||||||
|
onExit: config.onExit ?? (() => { }),
|
||||||
|
debug: config.debug ?? false,
|
||||||
|
};
|
||||||
|
this.url = new URL(this.config.wsUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
private log(message: string) {
|
||||||
|
if (!this.config.debug) return;
|
||||||
|
const timestamp = new Date().toISOString();
|
||||||
|
const msg = `[${timestamp}] ${message}`;
|
||||||
|
console.log(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseMessage(data: Buffer): ParsedMessage | null {
|
||||||
|
const result: ParsedMessage = { type: "unknown", raw: data };
|
||||||
|
|
||||||
|
if (data.length < 14) {
|
||||||
|
result.type = "raw";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const prefix = data.slice(0, 13);
|
||||||
|
const msgType = prefix[0];
|
||||||
|
const jsonStart = data.indexOf(0x71); // 0x71 = 'q'
|
||||||
|
|
||||||
|
if (jsonStart !== -1) {
|
||||||
|
try {
|
||||||
|
const jsonStr = data.slice(jsonStart + 1).toString();
|
||||||
|
const payload = JSON.parse(jsonStr);
|
||||||
|
result.type = `binary(0x${msgType.toString(16)})`;
|
||||||
|
result.payload = payload;
|
||||||
|
|
||||||
|
// 特殊处理 sign 类型
|
||||||
|
if (payload.type === "sign" && this.config.onSign) {
|
||||||
|
this.config.onSign(payload);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} catch {
|
||||||
|
result.type = "binary(json-parse-error)";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.type = "raw";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
const { wsUrl, cookie, debug } = this.config;
|
||||||
|
this.log(`Connecting to ${wsUrl}...`);
|
||||||
|
|
||||||
|
this.ws = new WebSocket(wsUrl, {
|
||||||
|
headers: {
|
||||||
|
"Origin": this.url.origin,
|
||||||
|
"Cookie": cookie,
|
||||||
|
"Cache-Control": "no-cache",
|
||||||
|
"Accept-Language": "zh-CN,zh;q=0.9",
|
||||||
|
"Pragma": "no-cache",
|
||||||
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
|
||||||
|
"Sec-WebSocket-Extensions": "permessage-deflate",
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.ws.on("open", () => {
|
||||||
|
debug && this.log("Connected!");
|
||||||
|
this.reconnectAttempts = 0;
|
||||||
|
this.config.onConnect();
|
||||||
|
this.startPing();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.ws.on("message", (data: any) => {
|
||||||
|
if (Buffer.isBuffer(data)) {
|
||||||
|
const parsed = this.parseMessage(data);
|
||||||
|
this.config.onMessage(parsed?.raw ?? data);
|
||||||
|
|
||||||
|
this.messageHandlers.forEach(handler => {
|
||||||
|
if (parsed) handler(parsed);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.config.onMessage(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.ws.on("close", (code: number) => {
|
||||||
|
debug && this.log(`Disconnected (code: ${code})`);
|
||||||
|
this.stopPing();
|
||||||
|
this.config.onDisconnect(code);
|
||||||
|
this.handleReconnect();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.ws.on("error", (err: Error) => {
|
||||||
|
debug && this.log(`Error: ${err.message}`);
|
||||||
|
this.config.onError(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private startPing() {
|
||||||
|
this.stopPing();
|
||||||
|
this.pingTimer = setInterval(() => {
|
||||||
|
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
||||||
|
this.ws.ping();
|
||||||
|
this.log("Sent ping");
|
||||||
|
}
|
||||||
|
}, this.config.pingInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
private stopPing() {
|
||||||
|
if (this.pingTimer) {
|
||||||
|
clearInterval(this.pingTimer);
|
||||||
|
this.pingTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleReconnect() {
|
||||||
|
if (this.reconnectAttempts >= this.config.maxReconnectAttempts) {
|
||||||
|
this.log(`Max reconnect attempts (${this.config.maxReconnectAttempts}) reached. Giving up.`);
|
||||||
|
this.config.onExit(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.reconnectAttempts++;
|
||||||
|
this.log(`Reconnecting in ${this.config.reconnectInterval}ms... (attempt ${this.reconnectAttempts}/${this.config.maxReconnectAttempts})`);
|
||||||
|
setTimeout(() => this.connect(), this.config.reconnectInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMessage(handler: MessageHandler) {
|
||||||
|
this.messageHandlers.add(handler);
|
||||||
|
return () => this.messageHandlers.delete(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect() {
|
||||||
|
this.stopPing();
|
||||||
|
if (this.ws) {
|
||||||
|
this.ws.close();
|
||||||
|
this.config.onExit(0);
|
||||||
|
this.ws = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 便捷函数:快速创建并启动
|
||||||
|
export function createKeepAlive(config: KeepAliveConfig): WSKeepAlive {
|
||||||
|
const client = new WSKeepAlive(config);
|
||||||
|
client.connect();
|
||||||
|
return client;
|
||||||
|
}
|
||||||
13
src/workspace/keep-worker.ts
Normal file
13
src/workspace/keep-worker.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { createKeepAlive } from '@kevisual/cnb/keep';
|
||||||
|
|
||||||
|
const wsUrl = process.argv[2];
|
||||||
|
const cookie = process.argv[3];
|
||||||
|
|
||||||
|
createKeepAlive({
|
||||||
|
wsUrl,
|
||||||
|
cookie,
|
||||||
|
onConnect: () => console.log('已连接'),
|
||||||
|
debug: true
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on('SIGINT', () => process.exit(0));
|
||||||
13
test/keep-test.ts
Normal file
13
test/keep-test.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { createKeepAlive } from "@kevisual/cnb/keep";
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
"wss": "wss://cnb-dk4-1jgcjjqvc-001.cnb.space:443/stable-3c0b449c6e6e37b44a8a7938c0d8a3049926a64c?reconnectionToken=d70ab69b-5e92-471a-b3d2-31f554b468d4&reconnection=false&skipWebSocketFrames=false",
|
||||||
|
"cookie": "orange:workspace:cookie-session:cnb-dk4-1jgcjjqvc-001=01fea6db-d73f-4ce8-8929-36903ee7a266",
|
||||||
|
"url": "https://cnb-dk4-1jgcjjqvc-001.cnb.space/?folder=/workspace"
|
||||||
|
}
|
||||||
|
|
||||||
|
createKeepAlive({
|
||||||
|
wsUrl: config.wss,
|
||||||
|
cookie: config.cookie,
|
||||||
|
debug: true,
|
||||||
|
});
|
||||||
20
test/keep.ts
Normal file
20
test/keep.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// WebSocket Keep-Alive Client with node+ws
|
||||||
|
// import { createKeepAlive } from "../src/keep.ts";
|
||||||
|
import { createKeepAlive } from "../dist/keep.js";
|
||||||
|
|
||||||
|
const WS_URL = "wss://cnb-l6o-1jg7aoevl-001.cnb.space/stable-3c0b449c6e6e37b44a8a7938c0d8a3049926a64c?reconnectionToken=a6517530-9911-406b-a65f-0d9d4b3f0d6f&reconnection=false&skipWebSocketFrames=false";
|
||||||
|
const COOKIE = "orange:workspace:cookie-session:cnb-l6o-1jg7aoevl-001=1ba3d696-1805-4c6b-b109-222738be570f";
|
||||||
|
|
||||||
|
// 使用库创建客户端
|
||||||
|
const client = createKeepAlive({
|
||||||
|
wsUrl: WS_URL,
|
||||||
|
cookie: COOKIE,
|
||||||
|
debug: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听解析后的消息
|
||||||
|
client.onMessage((msg) => {
|
||||||
|
console.log(`[Received] ${msg.raw.length} bytes`);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("开始激活 WebSocket 连接...");
|
||||||
@@ -3,7 +3,7 @@ import { KnowledgeBase } from "../src/knowledge/index.ts";
|
|||||||
import { token, showMore, cookie } from "./common.ts";
|
import { token, showMore, cookie } from "./common.ts";
|
||||||
// group: "kevisual/test",
|
// group: "kevisual/test",
|
||||||
const repo = new KnowledgeBase({ token: token, cookie: cookie });
|
const repo = new KnowledgeBase({ token: token, cookie: cookie });
|
||||||
const repoName = "test-local-docs";
|
const repoName = "kevisual/starred-auto";
|
||||||
|
|
||||||
// const queryRes = await repo.getEmbeddingModels(repoName);
|
// const queryRes = await repo.getEmbeddingModels(repoName);
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ import { token, showMore, cookie } from "./common.ts";
|
|||||||
const repo = new Repo({ token: token, cookie: cookie });
|
const repo = new Repo({ token: token, cookie: cookie });
|
||||||
|
|
||||||
|
|
||||||
const listRes = await repo.getRepoList({ page: 1, page_size: 999, role: 'developer' });
|
const listRes = await repo.getRepoList({
|
||||||
|
page: 1, page_size: 999, role: 'developer',
|
||||||
|
flags: 'KnowledgeBase'
|
||||||
|
});
|
||||||
|
|
||||||
console.log("listRes", showMore(listRes), listRes.data?.length);
|
console.log("listRes", showMore(listRes), listRes.data?.length);
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"module": "NodeNext",
|
"module": "NodeNext",
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
|
"rootDir": ".",
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"typeRoots": [
|
"typeRoots": [
|
||||||
"./node_modules/@types",
|
"./node_modules/@types",
|
||||||
@@ -19,6 +20,7 @@
|
|||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"src/**/*",
|
"src/**/*",
|
||||||
"agent/**/*",
|
"mod.ts",
|
||||||
|
"agent/**/*"
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user