@kevisual/cnb 0.0.37 → 0.0.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent/app.ts +30 -12
- package/agent/main.ts +18 -0
- package/agent/modules/cnb-manager.ts +115 -0
- package/agent/opencode.ts +1 -1
- package/agent/routes/cnb-board/cnb-dev-env.ts +5 -15
- package/agent/routes/cnb-board/index.ts +3 -2
- package/agent/routes/cnb-env/check.ts +3 -2
- package/agent/routes/cnb-env/env.ts +5 -3
- package/agent/routes/cnb-env/vscode.ts +5 -3
- package/agent/routes/cnb-manager/index.ts +48 -0
- package/agent/routes/index.ts +8 -0
- package/agent/routes/issues/issue.ts +5 -3
- package/agent/routes/issues/list.ts +3 -2
- package/agent/routes/knowledge/ai.ts +5 -3
- package/agent/routes/repo/list.ts +3 -2
- package/agent/routes/repo/repo.ts +8 -5
- package/agent/routes/share/index.ts +1 -1
- package/agent/routes/workspace/index.ts +12 -6
- package/agent/routes/workspace/keep.ts +9 -5
- package/agent/routes/workspace/skills.ts +3 -2
- package/dist/cli.js +16382 -3861
- package/dist/keep.js +34 -16
- package/dist/opencode.js +19042 -6522
- package/dist/routes.d.ts +29 -54
- package/dist/routes.js +16339 -3818
- package/package.json +14 -6
- package/mod.ts +0 -1
- /package/agent/{command.ts → commander.ts} +0 -0
package/agent/app.ts
CHANGED
|
@@ -1,17 +1,35 @@
|
|
|
1
1
|
import { QueryRouterServer as App } from '@kevisual/router'
|
|
2
2
|
import { useContextKey } from '@kevisual/context'
|
|
3
|
-
import {
|
|
3
|
+
import { useKey } from '@kevisual/use-config'
|
|
4
4
|
import { CNB } from '../src/index.ts';
|
|
5
|
+
import { CNBManager } from './modules/cnb-manager.ts'
|
|
6
|
+
export const cnbManager = new CNBManager()
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
8
|
+
// CNB_TOKEN是降级兼容变量,推荐使用CNB_API_KEY
|
|
9
|
+
// CNB_TOKEN 是流水线自己就有的变量,但是权限比较小
|
|
10
|
+
const token = useKey('CNB_API_KEY') as string || useKey('CNB_TOKEN') as string
|
|
11
|
+
// cookie 变量是可选的
|
|
12
|
+
const cookie = useKey('CNB_COOKIE') as string
|
|
13
|
+
try {
|
|
14
|
+
cnbManager.addCNB({
|
|
15
|
+
username: 'default',
|
|
16
|
+
token: token,
|
|
17
|
+
cookie: cookie,
|
|
18
|
+
cnb: new CNB({ token: token, cookie: cookie })
|
|
19
|
+
})
|
|
20
|
+
} catch (error) {
|
|
21
|
+
|
|
22
|
+
}
|
|
23
|
+
export const cnb = (await cnbManager.getCNB({ username: 'default' })).cnb
|
|
24
|
+
export const app = await useContextKey<App>('app', () => {
|
|
16
25
|
return new App({})
|
|
17
|
-
})
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
export const notCNBCheck = (ctx: any) => {
|
|
29
|
+
const isCNB = useKey('CNB');
|
|
30
|
+
if (!isCNB) {
|
|
31
|
+
ctx.throw(400, '当前环境非 cnb-board 环境,无法获取 live 内容');
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
package/agent/main.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// import { RemoteApp } from '@kevisual/remote-app';
|
|
2
|
+
import { app } from './index.ts'
|
|
3
|
+
// import { QueryLoginNode } from '@kevisual/api/login-node';
|
|
4
|
+
// const queryLoginNode = new QueryLoginNode({});
|
|
5
|
+
// await queryLoginNode.init()
|
|
6
|
+
// const token = await queryLoginNode.getToken();
|
|
7
|
+
// app.createRouteList()
|
|
8
|
+
// const remoteApp = new RemoteApp({
|
|
9
|
+
// id: 'cnb-agent',
|
|
10
|
+
// token: token,
|
|
11
|
+
// url: 'https://kevisual.cn/ws/proxy',
|
|
12
|
+
// app: app as any,
|
|
13
|
+
// })
|
|
14
|
+
// const isConnected = await remoteApp.isConnect();
|
|
15
|
+
// if (isConnected) {
|
|
16
|
+
// console.log('Remote app connected successfully');
|
|
17
|
+
// remoteApp.listenProxy();
|
|
18
|
+
// }
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Result } from '@kevisual/query';
|
|
2
|
+
import { CNB } from '../../src/index.ts';
|
|
3
|
+
export const getConfig = async (opts: { token?: string }) => {
|
|
4
|
+
const res = await fetch('https://kevisual.cn/api/router', {
|
|
5
|
+
method: 'POST',
|
|
6
|
+
body: JSON.stringify({
|
|
7
|
+
path: 'config',
|
|
8
|
+
key: 'get',
|
|
9
|
+
data: {
|
|
10
|
+
key: "cnb_center_config.json"
|
|
11
|
+
}
|
|
12
|
+
}),
|
|
13
|
+
headers: {
|
|
14
|
+
'Content-Type': 'application/json',
|
|
15
|
+
'Authorization': `Bearer ${opts.token!}`
|
|
16
|
+
},
|
|
17
|
+
}).then(res => res.json());
|
|
18
|
+
return res as Result<{
|
|
19
|
+
id: string, key: 'cnb_center_config.json', data: {
|
|
20
|
+
CNB_API_KEY: string,
|
|
21
|
+
CNB_COOKIE: string
|
|
22
|
+
}
|
|
23
|
+
}>;
|
|
24
|
+
}
|
|
25
|
+
type CNBItem = {
|
|
26
|
+
username: string,
|
|
27
|
+
token: string,
|
|
28
|
+
cookie?: string
|
|
29
|
+
runAt?: number
|
|
30
|
+
owner?: boolean
|
|
31
|
+
cnb: CNB
|
|
32
|
+
}
|
|
33
|
+
export class CNBManager {
|
|
34
|
+
cnbMap: Map<string, CNBItem> = new Map()
|
|
35
|
+
constructor() {
|
|
36
|
+
setInterval(() => {
|
|
37
|
+
this.clearExpiredCNB()
|
|
38
|
+
}, 1000 * 60 * 30) // 每30分钟清理一次过期的 CNB 实例
|
|
39
|
+
}
|
|
40
|
+
getDefaultCNB() {
|
|
41
|
+
const cnbItem = this.cnbMap.get('default')
|
|
42
|
+
if (!cnbItem) {
|
|
43
|
+
throw new Error('Default CNB not found')
|
|
44
|
+
}
|
|
45
|
+
return cnbItem
|
|
46
|
+
}
|
|
47
|
+
async getCNB(opts?: { username?: string, kevisualToken?: string }): Promise<CNBItem | null> {
|
|
48
|
+
const username = opts?.username
|
|
49
|
+
const cnbItem = this.cnbMap.get(username)
|
|
50
|
+
if (cnbItem) {
|
|
51
|
+
cnbItem.runAt = Date.now()
|
|
52
|
+
return cnbItem
|
|
53
|
+
}
|
|
54
|
+
const res = await getConfig({ token: opts?.kevisualToken })
|
|
55
|
+
if (res.code === 200) {
|
|
56
|
+
const cookie = res.data?.data?.CNB_COOKIE
|
|
57
|
+
const token = res.data?.data?.CNB_API_KEY
|
|
58
|
+
if (token) {
|
|
59
|
+
return this.addCNB({ username, token, cookie })
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return null
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* 通过上下文获取 CNB 实例(直接返回 cnb 对象)
|
|
66
|
+
* @param ctx
|
|
67
|
+
* @returns CNB 实例
|
|
68
|
+
*/
|
|
69
|
+
async getContext(ctx: any) {
|
|
70
|
+
const tokenUser = ctx?.state?.tokenUser
|
|
71
|
+
const username = tokenUser?.username
|
|
72
|
+
if (!username) {
|
|
73
|
+
ctx.throw(403, 'Unauthorized')
|
|
74
|
+
}
|
|
75
|
+
if (username === 'default') {
|
|
76
|
+
return this.getDefaultCNB().cnb
|
|
77
|
+
}
|
|
78
|
+
const kevisualToken = ctx.query?.token;
|
|
79
|
+
const item = await this.getCNB({ username, kevisualToken });
|
|
80
|
+
if (!item) {
|
|
81
|
+
ctx.throw(400, '不存在的 CNB 配置项,请检查 登录 Token 是否正确,或添加 CNB 配置')
|
|
82
|
+
}
|
|
83
|
+
return item.cnb
|
|
84
|
+
}
|
|
85
|
+
addCNB(opts: Partial<CNBItem>) {
|
|
86
|
+
if (!opts.username || !opts.token) {
|
|
87
|
+
throw new Error('username and token are required')
|
|
88
|
+
}
|
|
89
|
+
const exist = this.cnbMap.get(opts.username)
|
|
90
|
+
if (exist) {
|
|
91
|
+
exist.runAt = Date.now()
|
|
92
|
+
return exist
|
|
93
|
+
}
|
|
94
|
+
const cnb = opts?.cnb || new CNB({ token: opts.token, cookie: opts.cookie });
|
|
95
|
+
opts.cnb = cnb;
|
|
96
|
+
opts.runAt = Date.now()
|
|
97
|
+
this.cnbMap.set(opts.username, opts as CNBItem)
|
|
98
|
+
return opts as CNBItem
|
|
99
|
+
}
|
|
100
|
+
// 定期清理过期的 CNB 实例,默认过期时间为 1 小时
|
|
101
|
+
clearExpiredCNB(expireTime = 1000 * 60 * 60) {
|
|
102
|
+
const now = Date.now()
|
|
103
|
+
for (const [username, item] of this.cnbMap.entries()) {
|
|
104
|
+
if (username === 'default') {
|
|
105
|
+
continue
|
|
106
|
+
}
|
|
107
|
+
if (item.runAt && now - item.runAt > expireTime) {
|
|
108
|
+
this.cnbMap.delete(username)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
clearUsername(username: string) {
|
|
113
|
+
this.cnbMap.delete(username)
|
|
114
|
+
}
|
|
115
|
+
}
|
package/agent/opencode.ts
CHANGED
|
@@ -1,23 +1,13 @@
|
|
|
1
|
-
import { app } from '../../app.ts';
|
|
1
|
+
import { app, notCNBCheck } from '../../app.ts';
|
|
2
2
|
import { useKey } from '@kevisual/context'
|
|
3
3
|
import { getLiveMdContent } from './live/live-content.ts';
|
|
4
4
|
import z from 'zod';
|
|
5
|
-
|
|
6
|
-
const isCNB = useKey('CNB');
|
|
7
|
-
if (!isCNB) {
|
|
8
|
-
ctx.body = {
|
|
9
|
-
title: '非 cnb-board 环境',
|
|
10
|
-
list: []
|
|
11
|
-
}
|
|
12
|
-
return true;
|
|
13
|
-
}
|
|
14
|
-
return false;
|
|
15
|
-
}
|
|
5
|
+
|
|
16
6
|
app.route({
|
|
17
7
|
path: 'cnb_board',
|
|
18
8
|
key: 'live',
|
|
19
9
|
description: '获取cnb-board live的mdContent内容',
|
|
20
|
-
middleware: ['auth
|
|
10
|
+
middleware: ['auth'],
|
|
21
11
|
metadata: {
|
|
22
12
|
args: {
|
|
23
13
|
more: z.boolean().optional().describe('是否获取更多系统信息,默认false'),
|
|
@@ -37,7 +27,7 @@ app.route({
|
|
|
37
27
|
path: 'cnb_board',
|
|
38
28
|
key: 'live_repo_info',
|
|
39
29
|
description: '获取cnb-board live的repo信息',
|
|
40
|
-
middleware: ['auth
|
|
30
|
+
middleware: ['auth']
|
|
41
31
|
}).define(async (ctx) => {
|
|
42
32
|
const repoSlug = useKey('CNB_REPO_SLUG') || '';
|
|
43
33
|
const repoName = useKey('CNB_REPO_NAME') || '';
|
|
@@ -90,7 +80,7 @@ app.route({
|
|
|
90
80
|
path: 'cnb_board',
|
|
91
81
|
key: 'live_build_info',
|
|
92
82
|
description: '获取cnb-board live的构建信息',
|
|
93
|
-
middleware: ['auth
|
|
83
|
+
middleware: ['auth']
|
|
94
84
|
}).define(async (ctx) => {
|
|
95
85
|
if (notCNBCheck(ctx)) return;
|
|
96
86
|
const labels = [
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { app } from '../../app.ts';
|
|
1
|
+
import { app, notCNBCheck } from '../../app.ts';
|
|
2
2
|
import './cnb-dev-env.ts';
|
|
3
3
|
import { useKey } from '@kevisual/context';
|
|
4
4
|
import { spawnSync } from 'node:child_process';
|
|
@@ -31,8 +31,9 @@ app.route({
|
|
|
31
31
|
path: 'cnb_board',
|
|
32
32
|
key: 'exit',
|
|
33
33
|
description: 'cnb的工作环境退出程序',
|
|
34
|
-
middleware: ['auth
|
|
34
|
+
middleware: ['auth'],
|
|
35
35
|
}).define(async (ctx) => {
|
|
36
|
+
if (notCNBCheck(ctx)) return;
|
|
36
37
|
const cmd = 'kill 1';
|
|
37
38
|
execCommand(cmd);
|
|
38
39
|
}).addTo(app);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createSkill } from '@kevisual/router';
|
|
2
|
-
import { app,
|
|
2
|
+
import { app, cnbManager } from '../../app.ts';
|
|
3
3
|
import { tool } from '@opencode-ai/plugin/tool';
|
|
4
4
|
|
|
5
5
|
|
|
@@ -7,7 +7,7 @@ app.route({
|
|
|
7
7
|
path: 'cnb',
|
|
8
8
|
key: 'user-check',
|
|
9
9
|
description: '检查用户登录状态,参数checkToken,default true; checkCookie, default false',
|
|
10
|
-
middleware: ['auth
|
|
10
|
+
middleware: ['auth'],
|
|
11
11
|
metadata: {
|
|
12
12
|
tags: ['opencode'],
|
|
13
13
|
...createSkill({
|
|
@@ -24,6 +24,7 @@ app.route({
|
|
|
24
24
|
const checkToken = ctx.query?.checkToken ?? true;
|
|
25
25
|
const checkCookie = ctx.query?.checkCookie ?? false;
|
|
26
26
|
let content = '';
|
|
27
|
+
const cnb = await cnbManager.getContext(ctx);
|
|
27
28
|
if (checkToken) {
|
|
28
29
|
const res = await cnb.user.getUser();
|
|
29
30
|
if (res?.code !== 200) {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { createSkill, tool } from '@kevisual/router';
|
|
2
|
-
import { app,
|
|
2
|
+
import { app, cnbManager } from '../../app.ts';
|
|
3
3
|
|
|
4
4
|
// 设置 CNB_COOKIE环境变量和获取环境变量,用于界面操作定制模块功能
|
|
5
5
|
app.route({
|
|
6
6
|
path: 'cnb',
|
|
7
7
|
key: 'set-cnb-cookie',
|
|
8
8
|
description: '设置当前cnb工作空间的cookie环境变量',
|
|
9
|
-
middleware: ['auth
|
|
9
|
+
middleware: ['auth'],
|
|
10
10
|
metadata: {
|
|
11
11
|
tags: ['opencode'],
|
|
12
12
|
...createSkill({
|
|
@@ -19,6 +19,7 @@ app.route({
|
|
|
19
19
|
})
|
|
20
20
|
}
|
|
21
21
|
}).define(async (ctx) => {
|
|
22
|
+
const cnb = await cnbManager.getContext(ctx);
|
|
22
23
|
const cookie = ctx.query?.cookie;
|
|
23
24
|
if (!cookie) {
|
|
24
25
|
ctx.body = { content: '请提供有效的cookie值' };
|
|
@@ -33,7 +34,7 @@ app.route({
|
|
|
33
34
|
path: 'cnb',
|
|
34
35
|
key: 'get-cnb-cookie',
|
|
35
36
|
description: '获取当前cnb工作空间的cookie环境变量',
|
|
36
|
-
middleware: ['auth
|
|
37
|
+
middleware: ['auth'],
|
|
37
38
|
metadata: {
|
|
38
39
|
tags: ['opencode'],
|
|
39
40
|
...createSkill({
|
|
@@ -43,6 +44,7 @@ app.route({
|
|
|
43
44
|
})
|
|
44
45
|
}
|
|
45
46
|
}).define(async (ctx) => {
|
|
47
|
+
const cnb = await cnbManager.getContext(ctx);
|
|
46
48
|
const cookie = cnb.cookie || '未设置cookie环境变量';
|
|
47
49
|
ctx.body = { content: `当前cnb工作空间的cookie环境变量为:${cookie}` };
|
|
48
50
|
}).addTo(app);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createSkill, tool } from '@kevisual/router';
|
|
2
|
-
import { app,
|
|
2
|
+
import { app, notCNBCheck } from '../../app.ts';
|
|
3
3
|
|
|
4
4
|
import { CNB_ENV } from "@/common/cnb-env.ts";
|
|
5
5
|
|
|
@@ -11,7 +11,7 @@ app.route({
|
|
|
11
11
|
path: 'cnb',
|
|
12
12
|
key: 'get-cnb-port-uri',
|
|
13
13
|
description: '获取当前cnb工作空间的port代理uri',
|
|
14
|
-
middleware: ['auth
|
|
14
|
+
middleware: ['auth'],
|
|
15
15
|
metadata: {
|
|
16
16
|
tags: ['opencode'],
|
|
17
17
|
...createSkill({
|
|
@@ -24,6 +24,7 @@ app.route({
|
|
|
24
24
|
})
|
|
25
25
|
}
|
|
26
26
|
}).define(async (ctx) => {
|
|
27
|
+
if (notCNBCheck(ctx)) return;
|
|
27
28
|
const port = ctx.query?.port || 51515;
|
|
28
29
|
const uri = CNB_ENV?.CNB_VSCODE_PROXY_URI as string || '';
|
|
29
30
|
const finalUri = uri.replace('{{port}}', port.toString());
|
|
@@ -40,7 +41,7 @@ app.route({
|
|
|
40
41
|
path: 'cnb',
|
|
41
42
|
key: 'get-cnb-vscode-uri',
|
|
42
43
|
description: '获取当前cnb工作空间的vscode代理uri, 包括多种访问方式, 如web、vscode、codebuddy、cursor、ssh',
|
|
43
|
-
middleware: ['auth
|
|
44
|
+
middleware: ['auth'],
|
|
44
45
|
metadata: {
|
|
45
46
|
tags: ['opencode'],
|
|
46
47
|
...createSkill({
|
|
@@ -58,6 +59,7 @@ app.route({
|
|
|
58
59
|
})
|
|
59
60
|
}
|
|
60
61
|
}).define(async (ctx) => {
|
|
62
|
+
if (notCNBCheck(ctx)) return;
|
|
61
63
|
const web = ctx.query?.web ?? false;
|
|
62
64
|
const vscode = ctx.query?.vscode ?? true; // 默认true
|
|
63
65
|
const codebuddy = ctx.query?.codebuddy ?? false;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { app, cnbManager } from '../../app.ts';
|
|
2
|
+
|
|
3
|
+
// "列出我的代码仓库,search blog"
|
|
4
|
+
// 列出我的知识库的代码仓库
|
|
5
|
+
app.route({
|
|
6
|
+
path: 'cnb',
|
|
7
|
+
key: 'clear-me-manager',
|
|
8
|
+
description: '清理我的cnb-manager记录',
|
|
9
|
+
middleware: ['auth'],
|
|
10
|
+
|
|
11
|
+
}).define(async (ctx) => {
|
|
12
|
+
const tokenUser = ctx.tokenUser;
|
|
13
|
+
if (!tokenUser) {
|
|
14
|
+
ctx.throw(401, '未授权');
|
|
15
|
+
}
|
|
16
|
+
const username = tokenUser.username;
|
|
17
|
+
if (!username) {
|
|
18
|
+
ctx.throw(400, '无效的用户信息');
|
|
19
|
+
}
|
|
20
|
+
if (username !== 'default') {
|
|
21
|
+
cnbManager.clearUsername(username);
|
|
22
|
+
}
|
|
23
|
+
ctx.body = { content: '已清理cnb-manager记录' };
|
|
24
|
+
}).addTo(app);
|
|
25
|
+
|
|
26
|
+
app.route({
|
|
27
|
+
path: 'cnb',
|
|
28
|
+
key: 'get-my-config',
|
|
29
|
+
description: '获取我的cnb配置',
|
|
30
|
+
middleware: ['auth'],
|
|
31
|
+
}).define(async (ctx) => {
|
|
32
|
+
const username = ctx.tokenUser?.username;
|
|
33
|
+
const token = ctx.query?.token;
|
|
34
|
+
if (!username) {
|
|
35
|
+
ctx.throw(400, '未授权');
|
|
36
|
+
}
|
|
37
|
+
if (!token) {
|
|
38
|
+
ctx.throw(400, '缺少token参数');
|
|
39
|
+
}
|
|
40
|
+
const cnbItem = await cnbManager.getCNB({ username, kevisualToken: token });
|
|
41
|
+
if (!cnbItem) {
|
|
42
|
+
ctx.throw(404, '未找到cnb-manager记录');
|
|
43
|
+
}
|
|
44
|
+
ctx.body = {
|
|
45
|
+
token: cnbItem.token,
|
|
46
|
+
cookie: cnbItem.cookie,
|
|
47
|
+
}
|
|
48
|
+
}).addTo(app);
|
package/agent/routes/index.ts
CHANGED
|
@@ -8,6 +8,8 @@ import './knowledge/index.ts'
|
|
|
8
8
|
import './issues/index.ts'
|
|
9
9
|
import './cnb-board/index.ts';
|
|
10
10
|
import './share/index.ts';
|
|
11
|
+
import './cnb-manager/index.ts';
|
|
12
|
+
|
|
11
13
|
/**
|
|
12
14
|
* 验证上下文中的 App ID 是否与指定的 App ID 匹配
|
|
13
15
|
* @param {any} ctx - 上下文对象,可能包含 appId 属性
|
|
@@ -32,6 +34,9 @@ app.route({
|
|
|
32
34
|
}).define(async (ctx) => {
|
|
33
35
|
// ctx.body = 'Auth Route';
|
|
34
36
|
if (checkAppId(ctx, app.appId)) {
|
|
37
|
+
ctx.state.tokenUser = {
|
|
38
|
+
username: 'default',
|
|
39
|
+
}
|
|
35
40
|
return;
|
|
36
41
|
}
|
|
37
42
|
}).addTo(app, { overwrite: false });
|
|
@@ -43,6 +48,9 @@ app.route({
|
|
|
43
48
|
}).define(async (ctx) => {
|
|
44
49
|
// ctx.body = 'Admin Auth Route';
|
|
45
50
|
if (checkAppId(ctx, app.appId)) {
|
|
51
|
+
ctx.state.tokenUser = {
|
|
52
|
+
username: 'default',
|
|
53
|
+
}
|
|
46
54
|
return;
|
|
47
55
|
}
|
|
48
56
|
}).addTo(app, { overwrite: false });
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createSkill, tool } from '@kevisual/router';
|
|
2
|
-
import { app,
|
|
2
|
+
import { app, cnbManager } from '../../app.ts';
|
|
3
3
|
import { IssueItem } from '@/index.ts';
|
|
4
4
|
|
|
5
5
|
// 创建cnb issue, 仓库为 kevisual/kevisual 标题为 "自动化测试创建issue", 内容为 "这是通过API创建的issue,用于测试目的", body: "这是通过API创建的issue,用于测试目的"
|
|
@@ -7,7 +7,7 @@ app.route({
|
|
|
7
7
|
path: 'cnb',
|
|
8
8
|
key: 'create-issue',
|
|
9
9
|
description: '创建 Issue, 参数 repo, title, body, assignees, labels, priority',
|
|
10
|
-
middleware: ['auth
|
|
10
|
+
middleware: ['auth'],
|
|
11
11
|
metadata: {
|
|
12
12
|
tags: ['opencode'],
|
|
13
13
|
...createSkill({
|
|
@@ -25,6 +25,7 @@ app.route({
|
|
|
25
25
|
})
|
|
26
26
|
}
|
|
27
27
|
}).define(async (ctx) => {
|
|
28
|
+
const cnb = await cnbManager.getContext(ctx);
|
|
28
29
|
const repo = ctx.query?.repo;
|
|
29
30
|
const title = ctx.query?.title;
|
|
30
31
|
const body = ctx.query?.body;
|
|
@@ -51,7 +52,7 @@ app.route({
|
|
|
51
52
|
path: 'cnb',
|
|
52
53
|
key: 'complete-issue',
|
|
53
54
|
description: '完成 Issue, 参数 repo, issueNumber',
|
|
54
|
-
middleware: ['auth
|
|
55
|
+
middleware: ['auth'],
|
|
55
56
|
metadata: {
|
|
56
57
|
tags: ['opencode'],
|
|
57
58
|
...createSkill({
|
|
@@ -66,6 +67,7 @@ app.route({
|
|
|
66
67
|
})
|
|
67
68
|
}
|
|
68
69
|
}).define(async (ctx) => {
|
|
70
|
+
const cnb = await cnbManager.getContext(ctx);
|
|
69
71
|
const repo = ctx.query?.repo;
|
|
70
72
|
const issueNumber = ctx.query?.issueNumber;
|
|
71
73
|
const state = ctx.query?.state ?? 'closed';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createSkill, tool } from '@kevisual/router';
|
|
2
|
-
import { app,
|
|
2
|
+
import { app, cnbManager } from '../../app.ts';
|
|
3
3
|
import { useKey } from '@kevisual/context';
|
|
4
4
|
|
|
5
5
|
// 查询 Issue 列表 repo是 kevisual/kevisual
|
|
@@ -7,7 +7,7 @@ app.route({
|
|
|
7
7
|
path: 'cnb',
|
|
8
8
|
key: 'list-issues',
|
|
9
9
|
description: '查询 Issue 列表, 参数 repo, state, keyword, labels, page, page_size 等',
|
|
10
|
-
middleware: ['auth
|
|
10
|
+
middleware: ['auth'],
|
|
11
11
|
metadata: {
|
|
12
12
|
tags: ['opencode'],
|
|
13
13
|
...createSkill({
|
|
@@ -26,6 +26,7 @@ app.route({
|
|
|
26
26
|
})
|
|
27
27
|
}
|
|
28
28
|
}).define(async (ctx) => {
|
|
29
|
+
const cnb = await cnbManager.getContext(ctx);
|
|
29
30
|
const repo = ctx.query?.repo || useKey('CNB_REPO_SLUG_LOWERCASE');
|
|
30
31
|
const state = ctx.query?.state;
|
|
31
32
|
const keyword = ctx.query?.keyword;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createSkill, tool } from '@kevisual/router';
|
|
2
|
-
import { app,
|
|
2
|
+
import { app, cnbManager } from '../../app.ts';
|
|
3
3
|
import { CNBChat } from '@kevisual/ai/browser'
|
|
4
4
|
import { useKey } from '@kevisual/context';
|
|
5
5
|
|
|
@@ -13,7 +13,7 @@ app.route({
|
|
|
13
13
|
path: 'cnb',
|
|
14
14
|
key: 'cnb-ai-chat',
|
|
15
15
|
description: '调用cnb的知识库ai对话功能进行聊天',
|
|
16
|
-
middleware: ['auth
|
|
16
|
+
middleware: ['auth'],
|
|
17
17
|
metadata: {
|
|
18
18
|
tags: ['opencode'],
|
|
19
19
|
...createSkill({
|
|
@@ -27,6 +27,7 @@ app.route({
|
|
|
27
27
|
})
|
|
28
28
|
}
|
|
29
29
|
}).define(async (ctx) => {
|
|
30
|
+
const cnb = await cnbManager.getContext(ctx);
|
|
30
31
|
const question = ctx.query?.question;
|
|
31
32
|
if (!question) {
|
|
32
33
|
ctx.body = { content: '请提供有效的消息内容' };
|
|
@@ -89,7 +90,7 @@ app.route({
|
|
|
89
90
|
path: 'cnb',
|
|
90
91
|
key: 'cnb-rag-query',
|
|
91
92
|
description: '调用cnb的知识库RAG查询功能进行问答',
|
|
92
|
-
middleware: ['auth
|
|
93
|
+
middleware: ['auth'],
|
|
93
94
|
metadata: {
|
|
94
95
|
tags: ['opencode'],
|
|
95
96
|
...createSkill({
|
|
@@ -103,6 +104,7 @@ app.route({
|
|
|
103
104
|
})
|
|
104
105
|
}
|
|
105
106
|
}).define(async (ctx) => {
|
|
107
|
+
const cnb = await cnbManager.getContext(ctx);
|
|
106
108
|
const question = ctx.query?.question;
|
|
107
109
|
if (!question) {
|
|
108
110
|
ctx.body = { content: '请提供有效的消息内容' };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createSkill, tool } from '@kevisual/router';
|
|
2
|
-
import { app,
|
|
2
|
+
import { app, cnbManager } from '../../app.ts';
|
|
3
3
|
|
|
4
4
|
// "列出我的代码仓库,search blog"
|
|
5
5
|
// 列出我的知识库的代码仓库
|
|
@@ -7,7 +7,7 @@ app.route({
|
|
|
7
7
|
path: 'cnb',
|
|
8
8
|
key: 'list-repos',
|
|
9
9
|
description: '列出我的代码仓库',
|
|
10
|
-
middleware: ['auth
|
|
10
|
+
middleware: ['auth'],
|
|
11
11
|
metadata: {
|
|
12
12
|
tags: ['opencode'],
|
|
13
13
|
...createSkill({
|
|
@@ -22,6 +22,7 @@ app.route({
|
|
|
22
22
|
})
|
|
23
23
|
}
|
|
24
24
|
}).define(async (ctx) => {
|
|
25
|
+
const cnb = await cnbManager.getContext(ctx);
|
|
25
26
|
const search = ctx.query?.search;
|
|
26
27
|
const pageSize = ctx.query?.pageSize || 9999;
|
|
27
28
|
const flags = ctx.query?.flags;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { app,
|
|
1
|
+
import { app, cnbManager } from '../../app.ts';
|
|
2
2
|
import { createSkill, Skill, tool } from '@kevisual/router'
|
|
3
3
|
|
|
4
4
|
// 创建一个仓库 kevisual/test-repo
|
|
@@ -6,7 +6,7 @@ app.route({
|
|
|
6
6
|
path: 'cnb',
|
|
7
7
|
key: 'create-repo',
|
|
8
8
|
description: '创建代码仓库, 参数name, visibility, description',
|
|
9
|
-
middleware: ['auth
|
|
9
|
+
middleware: ['auth'],
|
|
10
10
|
metadata: {
|
|
11
11
|
tags: ['opencode'],
|
|
12
12
|
...createSkill({
|
|
@@ -21,6 +21,7 @@ app.route({
|
|
|
21
21
|
})
|
|
22
22
|
}
|
|
23
23
|
}).define(async (ctx) => {
|
|
24
|
+
const cnb = await cnbManager.getContext(ctx);
|
|
24
25
|
const name = ctx.query?.name;
|
|
25
26
|
const visibility = ctx.query?.visibility ?? 'public';
|
|
26
27
|
const description = ctx.query?.description ?? '';
|
|
@@ -46,7 +47,7 @@ app.route({
|
|
|
46
47
|
path: 'cnb',
|
|
47
48
|
key: 'create-repo-file',
|
|
48
49
|
description: '在代码仓库中创建文件, repoName, filePath, content, encoding。使用CNB_COOKIE进行鉴权',
|
|
49
|
-
middleware: ['auth
|
|
50
|
+
middleware: ['auth'],
|
|
50
51
|
metadata: {
|
|
51
52
|
tags: ['opencode'],
|
|
52
53
|
...createSkill({
|
|
@@ -62,6 +63,7 @@ app.route({
|
|
|
62
63
|
})
|
|
63
64
|
}
|
|
64
65
|
}).define(async (ctx) => {
|
|
66
|
+
const cnb = await cnbManager.getContext(ctx);
|
|
65
67
|
const repoName = ctx.query?.repoName;
|
|
66
68
|
const filePath = ctx.query?.filePath;
|
|
67
69
|
const content = ctx.query?.content;
|
|
@@ -85,7 +87,7 @@ app.route({
|
|
|
85
87
|
path: 'cnb',
|
|
86
88
|
key: 'delete-repo',
|
|
87
89
|
description: '删除代码仓库, 参数name',
|
|
88
|
-
middleware: ['auth
|
|
90
|
+
middleware: ['auth'],
|
|
89
91
|
metadata: {
|
|
90
92
|
tags: ['opencode'],
|
|
91
93
|
...createSkill({
|
|
@@ -98,12 +100,13 @@ app.route({
|
|
|
98
100
|
})
|
|
99
101
|
}
|
|
100
102
|
}).define(async (ctx) => {
|
|
103
|
+
const cnb = await cnbManager.getContext(ctx);
|
|
101
104
|
const name = ctx.query?.name;
|
|
102
105
|
|
|
103
106
|
if (!name) {
|
|
104
107
|
ctx.throw(400, '缺少参数 name');
|
|
105
108
|
}
|
|
106
109
|
|
|
107
|
-
const res = await cnb.repo.
|
|
110
|
+
const res = await cnb.repo.deleteRepoCookie(name);
|
|
108
111
|
ctx.forward(res);
|
|
109
112
|
}).addTo(app);
|