@kevisual/cnb 0.0.75 → 0.0.77
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/routes/knowledge/embedding.ts +166 -0
- package/agent/routes/knowledge/index.ts +2 -1
- package/agent/routes/labels/index.ts +1 -0
- package/agent/routes/labels/tags.ts +76 -0
- package/dist/cli-live.js +42 -24
- package/dist/cli.js +933 -381
- package/dist/keep.js +34 -16
- package/dist/npc.js +921 -370
- package/dist/opencode.js +918 -366
- package/dist/routes.d.ts +77 -32
- package/dist/routes.js +905 -353
- package/package.json +2 -2
- package/src/cnb-core.ts +26 -11
- package/src/knowledge/index.ts +81 -22
- package/src/labels/repo-label.ts +54 -1
- package/src/mission/index.ts +11 -4
- package/src/issue/issue-alive/issues-alive.html +0 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kevisual/cnb",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.77",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"basename": "/root/cnb",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"ai": "^6.0.158",
|
|
49
49
|
"commander": "^14.0.3",
|
|
50
50
|
"dayjs": "^1.11.20",
|
|
51
|
-
"dotenv": "^17.4.
|
|
51
|
+
"dotenv": "^17.4.2",
|
|
52
52
|
"fast-glob": "^3.3.3",
|
|
53
53
|
"zod": "^4.3.6"
|
|
54
54
|
},
|
package/src/cnb-core.ts
CHANGED
|
@@ -7,7 +7,8 @@ export type CNBCoreOptions<T = {}> = {
|
|
|
7
7
|
cnb?: CNBCore;
|
|
8
8
|
cors?: {
|
|
9
9
|
baseUrl?: string
|
|
10
|
-
}
|
|
10
|
+
},
|
|
11
|
+
openapi?: boolean;
|
|
11
12
|
} & T;
|
|
12
13
|
|
|
13
14
|
export type RequestOptions = {
|
|
@@ -17,20 +18,24 @@ export type RequestOptions = {
|
|
|
17
18
|
body?: any;
|
|
18
19
|
params?: Record<string, any>;
|
|
19
20
|
headers?: Record<string, any>;
|
|
21
|
+
token?: string;
|
|
20
22
|
useCookie?: boolean;
|
|
21
23
|
useOrigin?: boolean;
|
|
22
24
|
};
|
|
23
|
-
const
|
|
25
|
+
const API_BASE_URL = 'https://api.cnb.cool'
|
|
24
26
|
const API_HACK_URL = 'https://cnb.cool'
|
|
27
|
+
const API_BASE_OPEN_URL = 'https://cn.cool/openapi'
|
|
25
28
|
export class CNBCore {
|
|
26
|
-
baseURL =
|
|
29
|
+
baseURL = API_BASE_URL;
|
|
27
30
|
hackURL = API_HACK_URL;
|
|
28
31
|
public token: string;
|
|
29
32
|
public cookie?: string;
|
|
30
33
|
isCors: boolean;
|
|
34
|
+
openapi?: boolean;
|
|
31
35
|
constructor(options: CNBCoreOptions) {
|
|
32
36
|
this.token = options.token;
|
|
33
37
|
this.cookie = options.cookie;
|
|
38
|
+
this.openapi = options.openapi;
|
|
34
39
|
if (options?.cnb) {
|
|
35
40
|
if (!options.token) {
|
|
36
41
|
this.token = options.cnb.token;
|
|
@@ -39,14 +44,20 @@ export class CNBCore {
|
|
|
39
44
|
this.cookie = options.cnb.cookie;
|
|
40
45
|
}
|
|
41
46
|
}
|
|
47
|
+
if (options?.openapi) {
|
|
48
|
+
this.baseURL = API_BASE_OPEN_URL;
|
|
49
|
+
}
|
|
42
50
|
if (options?.cors?.baseUrl) {
|
|
43
|
-
this.baseURL = options.cors.baseUrl + '/' +
|
|
44
|
-
this.hackURL = options.cors.baseUrl + '/' +
|
|
51
|
+
this.baseURL = options.cors.baseUrl + '/' + this.baseURL.replace('https://', '');
|
|
52
|
+
this.hackURL = options.cors.baseUrl + '/' + this.hackURL.replace('https://', '');
|
|
45
53
|
}
|
|
46
54
|
this.isCors = !!options?.cors?.baseUrl;
|
|
47
55
|
}
|
|
48
56
|
|
|
49
|
-
async request({ url, method = 'GET', data, params, headers, body, useCookie, useOrigin }: RequestOptions): Promise<any> {
|
|
57
|
+
async request({ url, method = 'GET', data, params, headers, body, useCookie, useOrigin, ...rest }: RequestOptions): Promise<any> {
|
|
58
|
+
if (!url.startsWith('http')) {
|
|
59
|
+
url = this.makeUrl(url);
|
|
60
|
+
}
|
|
50
61
|
const defaultHeaders: Record<string, string> = {
|
|
51
62
|
'Content-Type': 'application/json',
|
|
52
63
|
// 'Accept': 'application/json, application/vnd.cnb.api+json, application/vnd.cnb.web+json',
|
|
@@ -55,10 +66,13 @@ export class CNBCore {
|
|
|
55
66
|
if (this.token) {
|
|
56
67
|
defaultHeaders['Authorization'] = `Bearer ${this.token}`;
|
|
57
68
|
}
|
|
69
|
+
// 如果请求参数中有 token,则覆盖默认 token
|
|
70
|
+
if (rest.token) {
|
|
71
|
+
defaultHeaders['Authorization'] = `Bearer ${rest.token}`;
|
|
72
|
+
}
|
|
58
73
|
if (params) {
|
|
59
74
|
const queryString = new URLSearchParams(params).toString();
|
|
60
75
|
url += `?${queryString}`;
|
|
61
|
-
defaultHeaders['Accept'] = 'application/json';
|
|
62
76
|
}
|
|
63
77
|
const _headers = { ...defaultHeaders, ...headers };
|
|
64
78
|
let _body = undefined;
|
|
@@ -142,10 +156,11 @@ export class CNBCore {
|
|
|
142
156
|
return this.request({ url: fullUrl, method: 'PATCH', ...REST });
|
|
143
157
|
}
|
|
144
158
|
/**
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
159
|
+
* 通过 PUT 请求上传文件内容
|
|
160
|
+
* assets上传的时候,第一次会获取到一个上传 URL 和 token,然后使用这个方法将文件内容上传到指定的 URL
|
|
161
|
+
* @param data 包含 URL、token 和文件内容
|
|
162
|
+
* @returns 上传结果
|
|
163
|
+
*/
|
|
149
164
|
async putFile(data: { url: string, token: string, content: string | Buffer }): Promise<any> {
|
|
150
165
|
return this.request({
|
|
151
166
|
url: data.url,
|
package/src/knowledge/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CNBCore, CNBCoreOptions, Result } from "../cnb-core.ts";
|
|
1
|
+
import { CNBCore, CNBCoreOptions, RequestOptions, Result } from "../cnb-core.ts";
|
|
2
2
|
|
|
3
3
|
// https://cnb.cool/cnb/plugins/cnbcool/knowledge-base/-/blob/main/src/api.py
|
|
4
4
|
export class KnowledgeBase extends CNBCore {
|
|
@@ -27,31 +27,56 @@ export class KnowledgeBase extends CNBCore {
|
|
|
27
27
|
}
|
|
28
28
|
deleteBase(repo: string): Promise<Result<any>> {
|
|
29
29
|
const url = `/${repo}/-/knowledge/base`;
|
|
30
|
-
return this.
|
|
30
|
+
return this.delete({ url });
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* 未暴露
|
|
35
|
+
*
|
|
36
|
+
* 创建知识库接口,cnb 界面操作定制模块功能依赖该接口实现
|
|
35
37
|
* @param repo
|
|
36
38
|
* @param data
|
|
37
39
|
* @returns
|
|
38
40
|
*/
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
|
|
42
|
+
createKnowledgeBase(repo: string, params: {
|
|
43
|
+
/**
|
|
44
|
+
* hunyuan | bge-m3
|
|
45
|
+
*/
|
|
46
|
+
model_name: string;
|
|
41
47
|
include: string;
|
|
42
48
|
exclude: string;
|
|
49
|
+
chunk_size: number;
|
|
50
|
+
chunk_overlap: number;
|
|
51
|
+
text_separator: string;
|
|
43
52
|
issue_sync_enabled?: boolean;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
text_separator: string;
|
|
48
|
-
};
|
|
49
|
-
issue?: {
|
|
50
|
-
labels: string;
|
|
51
|
-
state: string;
|
|
52
|
-
};
|
|
53
|
+
issue_labels?: string;
|
|
54
|
+
issue_exclude_labels?: string;
|
|
55
|
+
issue_state?: string;
|
|
53
56
|
}): Promise<Result<any>> {
|
|
54
57
|
const url = `/${repo}/-/knowledge/base`;
|
|
58
|
+
const metadata: any = {
|
|
59
|
+
processing: {
|
|
60
|
+
chunk_size: params.chunk_size,
|
|
61
|
+
chunk_overlap: params.chunk_overlap,
|
|
62
|
+
text_separator: params.text_separator
|
|
63
|
+
},
|
|
64
|
+
version: "1.0"
|
|
65
|
+
};
|
|
66
|
+
if (params.issue_sync_enabled) {
|
|
67
|
+
metadata.issue = {
|
|
68
|
+
labels: params.issue_labels || "",
|
|
69
|
+
exclude_labels: params.issue_exclude_labels || "",
|
|
70
|
+
state: params.issue_state || ""
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
const data = {
|
|
74
|
+
embedding_model_name: params.model_name,
|
|
75
|
+
include: params.include,
|
|
76
|
+
exclude: params.exclude,
|
|
77
|
+
issue_sync_enabled: params.issue_sync_enabled || false,
|
|
78
|
+
metadata
|
|
79
|
+
};
|
|
55
80
|
return this.post({ url, data });
|
|
56
81
|
}
|
|
57
82
|
/**
|
|
@@ -74,22 +99,27 @@ export class KnowledgeBase extends CNBCore {
|
|
|
74
99
|
* @param text
|
|
75
100
|
* @returns
|
|
76
101
|
*/
|
|
77
|
-
getEmbedding(repo: string, text: string): Promise<Result<{
|
|
102
|
+
getEmbedding(repo: string, text: string): Promise<Result<{ embeddings: number[] }>> {
|
|
78
103
|
const url = `/${repo}/-/knowledge/embedding`;
|
|
79
104
|
return this.post({ url, data: { text } });
|
|
80
105
|
}
|
|
81
106
|
/**
|
|
82
|
-
*
|
|
107
|
+
* 未暴露
|
|
108
|
+
* 只能运行在流水线,使用流水线的CNB_TOKEN去使用
|
|
109
|
+
* 否则会报错:sn not found in meta
|
|
110
|
+
* opts的token必须是流水线的CNB_TOKEN,不能是用户的token
|
|
83
111
|
* @param repo
|
|
84
112
|
* @param chunksData
|
|
85
113
|
* @returns
|
|
86
114
|
*/
|
|
87
|
-
addDocument(repo: string,
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
115
|
+
addDocument(repo: string, AddDocument: AddDocument, opts?: RequestOptions): Promise<Result<null>> {
|
|
116
|
+
const url = `/${repo}/-/knowledge/documents/upsert-document-with-chunks`;
|
|
117
|
+
return this.post({ url, data: AddDocument, ...opts });
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* 未暴露
|
|
121
|
+
* @param repo
|
|
122
|
+
* @param paths
|
|
93
123
|
size: number;
|
|
94
124
|
}>;
|
|
95
125
|
}): Promise<Result<any>> {
|
|
@@ -114,7 +144,7 @@ export class KnowledgeBase extends CNBCore {
|
|
|
114
144
|
* @param page_size
|
|
115
145
|
* @returns
|
|
116
146
|
*/
|
|
117
|
-
|
|
147
|
+
listDocuments(repo: string, page: number = 1, page_size: number = 50): Promise<Result<any[]>> {
|
|
118
148
|
const url = `/${repo}/-/knowledge/documents`;
|
|
119
149
|
return this.get({ url, params: { page, page_size } });
|
|
120
150
|
}
|
|
@@ -143,4 +173,33 @@ type QueryRag = {
|
|
|
143
173
|
type: string; // code, text
|
|
144
174
|
url: string;
|
|
145
175
|
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
type AddDocument = {
|
|
179
|
+
// 文档路径,必填, 例如:docs/xxx.md
|
|
180
|
+
path: string;
|
|
181
|
+
// 文件名 xxx
|
|
182
|
+
name: string;
|
|
183
|
+
// 文件扩展名,例如:md
|
|
184
|
+
extension: string;
|
|
185
|
+
// 文件大小,单位:字节
|
|
186
|
+
size: number;
|
|
187
|
+
// 文件内容的 hash,(hashlib.md5(content.encode('utf-8')).hexdigest())
|
|
188
|
+
hash: string;
|
|
189
|
+
type: "code" | "issue"; // code, pdf
|
|
190
|
+
// 类似 https://cnb.cool/kevisual/starred-auto/-/blob/62ce3d724f6e5f2cfd4b84a1df7cf4a6eaf441d6/docs/11730342.md
|
|
191
|
+
url: string;
|
|
192
|
+
chunks: Array<{
|
|
193
|
+
// 文档的分块的内容
|
|
194
|
+
"content": string,
|
|
195
|
+
"hash": string,
|
|
196
|
+
"position": number,
|
|
197
|
+
"embedding": number[]
|
|
198
|
+
}>;
|
|
199
|
+
// 处理当前批次的索引, 从0开始
|
|
200
|
+
batch_index: number;
|
|
201
|
+
// 当前批次的总数, 必须大于0
|
|
202
|
+
batch_count: number;
|
|
203
|
+
// 是否是最后一批
|
|
204
|
+
is_last_batch: boolean;
|
|
146
205
|
}
|
package/src/labels/repo-label.ts
CHANGED
|
@@ -77,7 +77,44 @@ export class RepoLabel extends CNBCore {
|
|
|
77
77
|
}
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
|
-
|
|
80
|
+
async getAll(repo: string): Promise<Result<Label[]>> {
|
|
81
|
+
let labels: Label[] = [];
|
|
82
|
+
const pageSize = 99;
|
|
83
|
+
for (let page = 1; ; page++) {
|
|
84
|
+
const res = await this.list(repo, { page, page_size: pageSize });
|
|
85
|
+
if (res.code !== 200) {
|
|
86
|
+
return { code: res.code, message: res.message, data: labels };
|
|
87
|
+
}
|
|
88
|
+
labels = labels.concat(res.data);
|
|
89
|
+
if (res.data.length < pageSize) {
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return { code: 200, data: labels, message: '获取标签列表成功' };
|
|
94
|
+
}
|
|
95
|
+
async importLabels(opts: { repo: string, labels: PostLabelForm[] }): Promise<Result> {
|
|
96
|
+
const labels = opts.labels;
|
|
97
|
+
const repo = opts.repo;
|
|
98
|
+
const addLabels: Label[] = [];
|
|
99
|
+
for (const label of labels) {
|
|
100
|
+
try {
|
|
101
|
+
const res = await this.create(repo, label);
|
|
102
|
+
if (res.code === 200) {
|
|
103
|
+
addLabels.push(res.data);
|
|
104
|
+
} else {
|
|
105
|
+
if (res.code === 409) {
|
|
106
|
+
console.warn(`标签已存在 ${label.name},跳过创建`);
|
|
107
|
+
} else {
|
|
108
|
+
console.error(`创建标签失败 ${label.name}:`, res.message);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
} catch (e) {
|
|
112
|
+
console.error(`创建标签失败 ${label.name}:`, e);
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return { code: 200, data: { addLabels }, message: '导入标签成功' };
|
|
117
|
+
}
|
|
81
118
|
/**
|
|
82
119
|
* 创建一个标签
|
|
83
120
|
* @param repo 仓库路径
|
|
@@ -114,6 +151,22 @@ export class RepoLabel extends CNBCore {
|
|
|
114
151
|
const url = `/${repo}/-/labels/${encodeURIComponent(name)}`;
|
|
115
152
|
return this.delete({ url });
|
|
116
153
|
}
|
|
154
|
+
async removeLabels(opts: { repo: string, labels: string[] }): Promise<Result> {
|
|
155
|
+
const { repo, labels } = opts;
|
|
156
|
+
try {
|
|
157
|
+
for (const label of labels) {
|
|
158
|
+
const res = await this.remove(repo, label);
|
|
159
|
+
await new Promise(resolve => setTimeout(resolve, 100)); // 避免请求过快导致服务器拒绝服务
|
|
160
|
+
if (res.code !== 200) {
|
|
161
|
+
console.error(`删除标签失败 ${label}:`, res.message);
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return { code: 200, data: labels, message: '删除标签成功' };
|
|
166
|
+
} catch (error) {
|
|
167
|
+
return { code: 500, message: '删除标签失败', data: error };
|
|
168
|
+
}
|
|
169
|
+
}
|
|
117
170
|
}
|
|
118
171
|
|
|
119
172
|
type ListLabelsParams = {
|
package/src/mission/index.ts
CHANGED
|
@@ -112,10 +112,10 @@ export class Mission extends CNBCore {
|
|
|
112
112
|
/**
|
|
113
113
|
* 改变任务集可见性
|
|
114
114
|
* @param mission 任务集路径
|
|
115
|
-
* @param visibility 可见性 (
|
|
115
|
+
* @param visibility 可见性 (private 或 public)
|
|
116
116
|
* @returns 操作结果
|
|
117
117
|
*/
|
|
118
|
-
setVisibility(mission: string, visibility: '
|
|
118
|
+
setVisibility(mission: string, visibility: 'private' | 'public'): Promise<Result<any>> {
|
|
119
119
|
const url = `/${mission}/-/settings/set_visibility`;
|
|
120
120
|
return this.post({
|
|
121
121
|
url,
|
|
@@ -146,9 +146,16 @@ type GetMissionsParams = {
|
|
|
146
146
|
};
|
|
147
147
|
|
|
148
148
|
type CreateMissionData = {
|
|
149
|
+
/**
|
|
150
|
+
* 任务集名称,必填
|
|
151
|
+
*/
|
|
149
152
|
name: string;
|
|
150
153
|
description?: string;
|
|
151
|
-
visibility?: '
|
|
154
|
+
visibility?: 'private' | 'public';
|
|
155
|
+
/**
|
|
156
|
+
* 关联的仓库列表,格式为 `${group}/${repo}`,如 `my-group/my-repo`
|
|
157
|
+
*/
|
|
158
|
+
repos: string[];
|
|
152
159
|
};
|
|
153
160
|
|
|
154
161
|
type Missions4User = {
|
|
@@ -156,7 +163,7 @@ type Missions4User = {
|
|
|
156
163
|
name: string;
|
|
157
164
|
slug_path: string;
|
|
158
165
|
description: string;
|
|
159
|
-
visibility: '
|
|
166
|
+
visibility: 'private' | 'public';
|
|
160
167
|
created_at: string;
|
|
161
168
|
updated_at: string;
|
|
162
169
|
web_url: string;
|