@kevisual/cnb 0.0.3 → 0.0.6

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.
@@ -5,8 +5,8 @@ import './workspace/index.ts'
5
5
  import './call/index.ts'
6
6
  import './cnb-env/index.ts'
7
7
  import './knowledge/index.ts'
8
+ import './issues/index.ts'
8
9
 
9
- import { isEqual } from 'es-toolkit'
10
10
  /**
11
11
  * 验证上下文中的 App ID 是否与指定的 App ID 匹配
12
12
  * @param {any} ctx - 上下文对象,可能包含 appId 属性
@@ -0,0 +1,2 @@
1
+ import './list.ts'
2
+ import './issue.ts'
@@ -0,0 +1,82 @@
1
+ import { createSkill, tool } from '@kevisual/router';
2
+ import { app, cnb } from '../../app.ts';
3
+ import { IssueItem } from '@/index.ts';
4
+
5
+ // 创建cnb issue, 仓库为 kevisual/kevisual 标题为 "自动化测试创建issue", 内容为 "这是通过API创建的issue,用于测试目的", body: "这是通过API创建的issue,用于测试目的"
6
+ app.route({
7
+ path: 'cnb',
8
+ key: 'create-issue',
9
+ description: '创建 Issue, 参数 repo, title, body, assignees, labels, priority',
10
+ middleware: ['auth'],
11
+ metadata: {
12
+ tags: ['opencode'],
13
+ ...createSkill({
14
+ skill: 'create-issue',
15
+ title: '创建 Issue',
16
+ args: {
17
+ repo: tool.schema.string().describe('代码仓库名称, 如 my-user/my-repo'),
18
+ title: tool.schema.string().describe('Issue 标题'),
19
+ body: tool.schema.string().optional().describe('Issue 描述内容'),
20
+ assignees: tool.schema.array(tool.schema.string()).optional().describe('指派人列表'),
21
+ labels: tool.schema.array(tool.schema.string()).optional().describe('标签列表'),
22
+ priority: tool.schema.string().optional().describe('优先级'),
23
+ },
24
+ summary: '创建一个新的 Issue',
25
+ })
26
+ }
27
+ }).define(async (ctx) => {
28
+ const repo = ctx.query?.repo;
29
+ const title = ctx.query?.title;
30
+ const body = ctx.query?.body;
31
+ const assignees = ctx.query?.assignees;
32
+ const labels = ctx.query?.labels;
33
+ const priority = ctx.query?.priority;
34
+
35
+ if (!repo || !title) {
36
+ ctx.throw(400, '缺少参数 repo 或 title');
37
+ }
38
+
39
+ const res = await cnb.issue.createIssue(repo, {
40
+ title,
41
+ body,
42
+ assignees,
43
+ labels,
44
+ priority,
45
+ });
46
+ ctx.forward(res);
47
+ }).addTo(app);
48
+
49
+ // 完成 issue 8, 仓库是 kevisual/kevisaul
50
+ app.route({
51
+ path: 'cnb',
52
+ key: 'complete-issue',
53
+ description: '完成 Issue, 参数 repo, issueNumber',
54
+ middleware: ['auth'],
55
+ metadata: {
56
+ tags: ['opencode'],
57
+ ...createSkill({
58
+ skill: 'complete-issue',
59
+ title: '完成 CNB的任务Issue',
60
+ args: {
61
+ repo: tool.schema.string().describe('代码仓库名称, 如 my-user/my-repo'),
62
+ issueNumber: tool.schema.union([tool.schema.string(), tool.schema.number()]).describe('Issue 编号'),
63
+ state: tool.schema.string().optional().describe('Issue 状态,默认为 closed'),
64
+ },
65
+ summary: '完成一个 Issue(将 state 改为 closed)',
66
+ })
67
+ }
68
+ }).define(async (ctx) => {
69
+ const repo = ctx.query?.repo;
70
+ const issueNumber = ctx.query?.issueNumber;
71
+ const state = ctx.query?.state ?? 'closed';
72
+
73
+ if (!repo || !issueNumber) {
74
+ ctx.throw(400, '缺少参数 repo 或 issueNumber');
75
+ }
76
+ const iss: Partial<IssueItem> = { state: state };
77
+ if (iss.state === 'closed') {
78
+ iss.state_reason = 'completed';
79
+ }
80
+ const res = await cnb.issue.updateIssue(repo, issueNumber, iss);
81
+ ctx.forward(res);
82
+ }).addTo(app);
@@ -0,0 +1,50 @@
1
+ import { createSkill, tool } from '@kevisual/router';
2
+ import { app, cnb } from '../../app.ts';
3
+
4
+ // 查询 Issue 列表 repo是 kevisual/kevisual
5
+ app.route({
6
+ path: 'cnb',
7
+ key: 'list-issues',
8
+ description: '查询 Issue 列表, 参数 repo, state, keyword, labels, page, page_size 等',
9
+ middleware: ['auth'],
10
+ metadata: {
11
+ tags: ['opencode'],
12
+ ...createSkill({
13
+ skill: 'list-issues',
14
+ title: '查询 Issue 列表',
15
+ args: {
16
+ repo: tool.schema.string().describe('代码仓库名称, 如 my-user/my-repo'),
17
+ state: tool.schema.string().optional().describe('Issue 状态:open 或 closed'),
18
+ keyword: tool.schema.string().optional().describe('问题搜索关键词'),
19
+ labels: tool.schema.string().optional().describe('问题标签,多个用逗号分隔'),
20
+ page: tool.schema.number().optional().describe('分页页码,默认: 1'),
21
+ page_size: tool.schema.number().optional().describe('分页每页大小,默认: 30'),
22
+ order_by: tool.schema.string().optional().describe('排序方式,如 created_at, -updated_at'),
23
+ },
24
+ summary: '查询 Issue 列表',
25
+ })
26
+ }
27
+ }).define(async (ctx) => {
28
+ const repo = ctx.query?.repo;
29
+ const state = ctx.query?.state;
30
+ const keyword = ctx.query?.keyword;
31
+ const labels = ctx.query?.labels;
32
+ const page = ctx.query?.page ? Number(ctx.query.page) : undefined;
33
+ const page_size = ctx.query?.page_size ? Number(ctx.query.page_size) : undefined;
34
+ const order_by = ctx.query?.order_by;
35
+
36
+ if (!repo) {
37
+ ctx.throw(400, '缺少参数 repo');
38
+ }
39
+
40
+ const params: Record<string, any> = {};
41
+ if (state) params.state = state;
42
+ if (keyword) params.keyword = keyword;
43
+ if (labels) params.labels = labels;
44
+ if (page) params.page = page;
45
+ if (page_size) params.page_size = page_size;
46
+ if (order_by) params.order_by = order_by;
47
+
48
+ const res = await cnb.issue.getList(repo, params);
49
+ ctx.forward(res);
50
+ }).addTo(app);
package/dist/opencode.js CHANGED
@@ -9,7 +9,7 @@ var __export = (target, all) => {
9
9
  });
10
10
  };
11
11
 
12
- // node_modules/.pnpm/@kevisual+router@0.0.62/node_modules/@kevisual/router/dist/router.js
12
+ // node_modules/.pnpm/@kevisual+router@0.0.63_typescript@5.9.3/node_modules/@kevisual/router/dist/router.js
13
13
  import require$$1, { webcrypto } from "node:crypto";
14
14
  import require$$2 from "node:http";
15
15
  import require$$1$1 from "node:https";
@@ -2083,7 +2083,7 @@ class Doc {
2083
2083
  var version = {
2084
2084
  major: 4,
2085
2085
  minor: 3,
2086
- patch: 5
2086
+ patch: 6
2087
2087
  };
2088
2088
  var $ZodType = /* @__PURE__ */ $constructor("$ZodType", (inst, def) => {
2089
2089
  var _a;
@@ -3367,7 +3367,7 @@ var $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
3367
3367
  if (keyResult instanceof Promise) {
3368
3368
  throw new Error("Async schemas not supported in object keys currently");
3369
3369
  }
3370
- const checkNumericKey = typeof key === "string" && number$2.test(key) && keyResult.issues.length && keyResult.issues.some((iss) => iss.code === "invalid_type" && iss.expected === "number");
3370
+ const checkNumericKey = typeof key === "string" && number$2.test(key) && keyResult.issues.length;
3371
3371
  if (checkNumericKey) {
3372
3372
  const retryResult = def.keyType._zod.run({ value: Number(key), issues: [] }, ctx);
3373
3373
  if (retryResult instanceof Promise) {
@@ -10682,7 +10682,7 @@ function finalize(ctx, schema) {
10682
10682
  }
10683
10683
  }
10684
10684
  }
10685
- if (refSchema.$ref) {
10685
+ if (refSchema.$ref && refSeen.def) {
10686
10686
  for (const key in schema2) {
10687
10687
  if (key === "$ref" || key === "allOf")
10688
10688
  continue;
@@ -32161,7 +32161,7 @@ function date5(params) {
32161
32161
 
32162
32162
  // node_modules/.pnpm/zod@4.1.8/node_modules/zod/v4/classic/external.js
32163
32163
  config3(en_default());
32164
- // node_modules/.pnpm/@opencode-ai+plugin@1.1.36/node_modules/@opencode-ai/plugin/dist/tool.js
32164
+ // node_modules/.pnpm/@opencode-ai+plugin@1.1.39/node_modules/@opencode-ai/plugin/dist/tool.js
32165
32165
  function tool2(input) {
32166
32166
  return input;
32167
32167
  }
@@ -46252,7 +46252,7 @@ app.route({
46252
46252
  ctx.body = { content: `当前cnb工作空间的cookie环境变量为:${cookie}` };
46253
46253
  }).addTo(app);
46254
46254
 
46255
- // node_modules/.pnpm/@kevisual+ai@0.0.22/node_modules/@kevisual/ai/dist/ai-provider-browser.js
46255
+ // node_modules/.pnpm/@kevisual+ai@0.0.24/node_modules/@kevisual/ai/dist/ai-provider-browser.js
46256
46256
  var __create2 = Object.create;
46257
46257
  var __getProtoOf2 = Object.getPrototypeOf;
46258
46258
  var __defProp3 = Object.defineProperty;
@@ -66074,15 +66074,28 @@ class BaseChat {
66074
66074
  }
66075
66075
  class CNBChat extends BaseChat {
66076
66076
  static BASE_URL = "https://api.cnb.cool/{repo}/-/ai";
66077
+ repo;
66077
66078
  constructor(options) {
66078
66079
  const baseURL = CNBChat.BASE_URL.replace("{repo}", options.repo);
66079
- super({ ...options, baseURL });
66080
+ super({ model: "hunyuan-a13b", ...options, baseURL });
66080
66081
  }
66081
- query({ repo: repo2, ...rest }) {
66082
- const baseURL = "https://api.cnb.cool/{repo}/-/knowledge/base/query".replace("{repo}", repo2);
66083
- this.post(baseURL, {
66084
- data: rest
66082
+ async query(params) {
66083
+ const url4 = this.baseURL.replace("/ai", "/knowledge/base/query");
66084
+ const response = await this.post(url4, {
66085
+ data: {
66086
+ score_threshold: 0.62,
66087
+ top_k: 10,
66088
+ ...params
66089
+ }
66085
66090
  });
66091
+ if (!response.ok) {
66092
+ throw new Error(`query API error: ${response.status} ${response.statusText}`);
66093
+ }
66094
+ const res = await response.json();
66095
+ return {
66096
+ code: 200,
66097
+ data: res || []
66098
+ };
66086
66099
  }
66087
66100
  }
66088
66101
  var import_aes = __toESM2(require_aes(), 1);
@@ -66254,6 +66267,131 @@ ${item.chunk}
66254
66267
  ctx.body = { content: answer };
66255
66268
  }).addTo(app);
66256
66269
 
66270
+ // agent/routes/issues/list.ts
66271
+ app.route({
66272
+ path: "cnb",
66273
+ key: "list-issues",
66274
+ description: "查询 Issue 列表, 参数 repo, state, keyword, labels, page, page_size 等",
66275
+ middleware: ["auth"],
66276
+ metadata: {
66277
+ tags: ["opencode"],
66278
+ ...createSkill({
66279
+ skill: "list-issues",
66280
+ title: "查询 Issue 列表",
66281
+ args: {
66282
+ repo: tool.schema.string().describe("代码仓库名称, 如 my-user/my-repo"),
66283
+ state: tool.schema.string().optional().describe("Issue 状态:open 或 closed"),
66284
+ keyword: tool.schema.string().optional().describe("问题搜索关键词"),
66285
+ labels: tool.schema.string().optional().describe("问题标签,多个用逗号分隔"),
66286
+ page: tool.schema.number().optional().describe("分页页码,默认: 1"),
66287
+ page_size: tool.schema.number().optional().describe("分页每页大小,默认: 30"),
66288
+ order_by: tool.schema.string().optional().describe("排序方式,如 created_at, -updated_at")
66289
+ },
66290
+ summary: "查询 Issue 列表"
66291
+ })
66292
+ }
66293
+ }).define(async (ctx) => {
66294
+ const repo2 = ctx.query?.repo;
66295
+ const state = ctx.query?.state;
66296
+ const keyword = ctx.query?.keyword;
66297
+ const labels = ctx.query?.labels;
66298
+ const page = ctx.query?.page ? Number(ctx.query.page) : undefined;
66299
+ const page_size = ctx.query?.page_size ? Number(ctx.query.page_size) : undefined;
66300
+ const order_by = ctx.query?.order_by;
66301
+ if (!repo2) {
66302
+ ctx.throw(400, "缺少参数 repo");
66303
+ }
66304
+ const params = {};
66305
+ if (state)
66306
+ params.state = state;
66307
+ if (keyword)
66308
+ params.keyword = keyword;
66309
+ if (labels)
66310
+ params.labels = labels;
66311
+ if (page)
66312
+ params.page = page;
66313
+ if (page_size)
66314
+ params.page_size = page_size;
66315
+ if (order_by)
66316
+ params.order_by = order_by;
66317
+ const res = await cnb.issue.getList(repo2, params);
66318
+ ctx.forward(res);
66319
+ }).addTo(app);
66320
+
66321
+ // agent/routes/issues/issue.ts
66322
+ app.route({
66323
+ path: "cnb",
66324
+ key: "create-issue",
66325
+ description: "创建 Issue, 参数 repo, title, body, assignees, labels, priority",
66326
+ middleware: ["auth"],
66327
+ metadata: {
66328
+ tags: ["opencode"],
66329
+ ...createSkill({
66330
+ skill: "create-issue",
66331
+ title: "创建 Issue",
66332
+ args: {
66333
+ repo: tool.schema.string().describe("代码仓库名称, 如 my-user/my-repo"),
66334
+ title: tool.schema.string().describe("Issue 标题"),
66335
+ body: tool.schema.string().optional().describe("Issue 描述内容"),
66336
+ assignees: tool.schema.array(tool.schema.string()).optional().describe("指派人列表"),
66337
+ labels: tool.schema.array(tool.schema.string()).optional().describe("标签列表"),
66338
+ priority: tool.schema.string().optional().describe("优先级")
66339
+ },
66340
+ summary: "创建一个新的 Issue"
66341
+ })
66342
+ }
66343
+ }).define(async (ctx) => {
66344
+ const repo2 = ctx.query?.repo;
66345
+ const title = ctx.query?.title;
66346
+ const body = ctx.query?.body;
66347
+ const assignees = ctx.query?.assignees;
66348
+ const labels = ctx.query?.labels;
66349
+ const priority = ctx.query?.priority;
66350
+ if (!repo2 || !title) {
66351
+ ctx.throw(400, "缺少参数 repo 或 title");
66352
+ }
66353
+ const res = await cnb.issue.createIssue(repo2, {
66354
+ title,
66355
+ body,
66356
+ assignees,
66357
+ labels,
66358
+ priority
66359
+ });
66360
+ ctx.forward(res);
66361
+ }).addTo(app);
66362
+ app.route({
66363
+ path: "cnb",
66364
+ key: "complete-issue",
66365
+ description: "完成 Issue, 参数 repo, issueNumber",
66366
+ middleware: ["auth"],
66367
+ metadata: {
66368
+ tags: ["opencode"],
66369
+ ...createSkill({
66370
+ skill: "complete-issue",
66371
+ title: "完成 CNB的任务Issue",
66372
+ args: {
66373
+ repo: tool.schema.string().describe("代码仓库名称, 如 my-user/my-repo"),
66374
+ issueNumber: tool.schema.union([tool.schema.string(), tool.schema.number()]).describe("Issue 编号"),
66375
+ state: tool.schema.string().optional().describe("Issue 状态,默认为 closed")
66376
+ },
66377
+ summary: "完成一个 Issue(将 state 改为 closed)"
66378
+ })
66379
+ }
66380
+ }).define(async (ctx) => {
66381
+ const repo2 = ctx.query?.repo;
66382
+ const issueNumber = ctx.query?.issueNumber;
66383
+ const state = ctx.query?.state ?? "closed";
66384
+ if (!repo2 || !issueNumber) {
66385
+ ctx.throw(400, "缺少参数 repo 或 issueNumber");
66386
+ }
66387
+ const iss = { state };
66388
+ if (iss.state === "closed") {
66389
+ iss.state_reason = "completed";
66390
+ }
66391
+ const res = await cnb.issue.updateIssue(repo2, issueNumber, iss);
66392
+ ctx.forward(res);
66393
+ }).addTo(app);
66394
+
66257
66395
  // agent/routes/index.ts
66258
66396
  var checkAppId = (ctx, appId2) => {
66259
66397
  const _appId = ctx?.app?.appId;
@@ -66285,7 +66423,7 @@ if (!app.hasRoute("auth")) {
66285
66423
  }).addTo(app);
66286
66424
  }
66287
66425
 
66288
- // node_modules/.pnpm/@kevisual+router@0.0.62/node_modules/@kevisual/router/dist/opencode.js
66426
+ // node_modules/.pnpm/@kevisual+router@0.0.63_typescript@5.9.3/node_modules/@kevisual/router/dist/opencode.js
66289
66427
  function getDefaultExportFromCjs4(x) {
66290
66428
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
66291
66429
  }
@@ -68723,7 +68861,7 @@ class Doc4 {
68723
68861
  var version4 = {
68724
68862
  major: 4,
68725
68863
  minor: 3,
68726
- patch: 5
68864
+ patch: 6
68727
68865
  };
68728
68866
  var $ZodType4 = /* @__PURE__ */ $constructor4("$ZodType", (inst, def) => {
68729
68867
  var _a3;
@@ -70007,7 +70145,7 @@ var $ZodRecord4 = /* @__PURE__ */ $constructor4("$ZodRecord", (inst, def) => {
70007
70145
  if (keyResult instanceof Promise) {
70008
70146
  throw new Error("Async schemas not supported in object keys currently");
70009
70147
  }
70010
- const checkNumericKey = typeof key === "string" && number$22.test(key) && keyResult.issues.length && keyResult.issues.some((iss) => iss.code === "invalid_type" && iss.expected === "number");
70148
+ const checkNumericKey = typeof key === "string" && number$22.test(key) && keyResult.issues.length;
70011
70149
  if (checkNumericKey) {
70012
70150
  const retryResult = def.keyType._zod.run({ value: Number(key), issues: [] }, ctx);
70013
70151
  if (retryResult instanceof Promise) {
@@ -77322,7 +77460,7 @@ function finalize3(ctx, schema) {
77322
77460
  }
77323
77461
  }
77324
77462
  }
77325
- if (refSchema.$ref) {
77463
+ if (refSchema.$ref && refSeen.def) {
77326
77464
  for (const key in schema2) {
77327
77465
  if (key === "$ref" || key === "allOf")
77328
77466
  continue;
@@ -80870,8 +81008,11 @@ var createRouterAgentPluginFn = (opts) => {
80870
81008
  }
80871
81009
  return false;
80872
81010
  });
80873
- const AgentPlugin = async ({ project, client, $, directory, worktree }) => {
81011
+ const AgentPlugin = async (pluginInput) => {
81012
+ useContextKey3("plugin-input", () => pluginInput, true);
81013
+ const hooks = opts?.hooks ? await opts.hooks(pluginInput) : {};
80874
81014
  return {
81015
+ ...hooks,
80875
81016
  tool: {
80876
81017
  ...routes.reduce((acc, route) => {
80877
81018
  const metadata = route.metadata;
@@ -80903,9 +81044,9 @@ var createRouterAgentPluginFn = (opts) => {
80903
81044
  }
80904
81045
  };
80905
81046
  return acc;
80906
- }, {})
80907
- },
80908
- "tool.execute.before": async (opts2) => {}
81047
+ }, {}),
81048
+ ...hooks?.tool
81049
+ }
80909
81050
  };
80910
81051
  };
80911
81052
  return AgentPlugin;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kevisual/cnb",
3
- "version": "0.0.3",
3
+ "version": "0.0.6",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -18,12 +18,12 @@
18
18
  "packageManager": "pnpm@10.28.2",
19
19
  "type": "module",
20
20
  "devDependencies": {
21
- "@kevisual/ai": "^0.0.22",
21
+ "@kevisual/ai": "^0.0.24",
22
22
  "@kevisual/context": "^0.0.4",
23
23
  "@kevisual/types": "^0.0.12",
24
- "@opencode-ai/plugin": "^1.1.36",
25
- "@types/bun": "^1.3.6",
26
- "@types/node": "^25.0.10",
24
+ "@opencode-ai/plugin": "^1.1.39",
25
+ "@types/bun": "^1.3.7",
26
+ "@types/node": "^25.1.0",
27
27
  "dotenv": "^17.2.3"
28
28
  },
29
29
  "publishConfig": {
@@ -31,7 +31,7 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "@kevisual/query": "^0.0.38",
34
- "@kevisual/router": "^0.0.62",
34
+ "@kevisual/router": "^0.0.63",
35
35
  "@kevisual/use-config": "^1.0.28",
36
36
  "es-toolkit": "^1.44.0",
37
37
  "nanoid": "^5.1.6",
@@ -26,6 +26,7 @@ export type IssueItem = {
26
26
  author: IssueAuthor;
27
27
  labels: IssueLabel[];
28
28
 
29
+ body: string;
29
30
  last_acted_at: string;
30
31
  number: string;
31
32
  priority: string;