@kevisual/cnb 0.0.54 → 0.0.56

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/dist/npc.js CHANGED
@@ -46838,7 +46838,8 @@ app.route({
46838
46838
  summary: "列出cnb代码仓库, 可选flags参数,如 KnowledgeBase",
46839
46839
  args: {
46840
46840
  search: tool.schema.string().optional().describe("搜索关键词"),
46841
- pageSize: tool.schema.number().optional().describe("每页数量,默认999"),
46841
+ page: tool.schema.number().optional().describe("分页页码,默认 1"),
46842
+ pageSize: tool.schema.number().optional().describe("每页数量,默认99"),
46842
46843
  flags: tool.schema.string().optional().describe("仓库标记,如果是知识库则填写 KnowledgeBase")
46843
46844
  }
46844
46845
  })
@@ -46846,13 +46847,17 @@ app.route({
46846
46847
  }).define(async (ctx) => {
46847
46848
  const cnb = await cnbManager.getContext(ctx);
46848
46849
  const search = ctx.query?.search;
46849
- const pageSize = ctx.query?.pageSize || 9999;
46850
+ const page = ctx.query?.page || 1;
46851
+ let pageSize = ctx.query?.pageSize || 99;
46850
46852
  const flags = ctx.query?.flags;
46851
46853
  const params = {};
46852
46854
  if (flags) {
46853
46855
  params.flags = flags;
46854
46856
  }
46855
- const res = await cnb.repo.getRepoList({ search, page_size: pageSize, role: "developer", ...params });
46857
+ if (pageSize > 99) {
46858
+ pageSize = 99;
46859
+ }
46860
+ const res = await cnb.repo.getRepoList({ search, page, page_size: pageSize + 1, role: "developer", ...params });
46856
46861
  if (res.code === 200) {
46857
46862
  const repos = res.data.map((item) => ({
46858
46863
  name: item.name,
@@ -46860,7 +46865,9 @@ app.route({
46860
46865
  description: item.description,
46861
46866
  web_url: item.web_url
46862
46867
  }));
46863
- ctx.body = { content: JSON.stringify(repos), list: res.data };
46868
+ const list = repos.slice(0, pageSize);
46869
+ const hasMore = repos.length > pageSize;
46870
+ ctx.body = { content: JSON.stringify(repos), list, hasMore, page, pageSize };
46864
46871
  } else {
46865
46872
  ctx.throw(500, "获取仓库列表失败");
46866
46873
  }
@@ -47453,6 +47460,57 @@ app.route({
47453
47460
  ctx.forward(res);
47454
47461
  }).addTo(app);
47455
47462
 
47463
+ // agent/routes/workspace/rerun.ts
47464
+ app.route({
47465
+ path: "cnb",
47466
+ key: "rerun",
47467
+ description: "重新启动工作区,定时任务",
47468
+ middleware: ["auth"],
47469
+ metadata: {
47470
+ args: {
47471
+ repo: zod_default.string().optional().describe("仓库名称,例如:owner/repo"),
47472
+ config: zod_default.string().optional().describe("工作区配置"),
47473
+ event: zod_default.string().optional().describe("触发事件来源,api_trigger_event")
47474
+ }
47475
+ }
47476
+ }).define(async (ctx) => {
47477
+ const cnb = await cnbManager.getContext(ctx);
47478
+ const repo2 = ctx.args.repo;
47479
+ const config3 = ctx.args.config;
47480
+ const event = ctx.args.event || "api_trigger_event";
47481
+ const res = await cnb.workspace.list({ status: "running" });
47482
+ if (res.code !== 200) {
47483
+ ctx.throw(500, res.message || "Failed to list workspaces");
47484
+ }
47485
+ const list = res.data?.list || [];
47486
+ const _list = list.filter((item) => {
47487
+ if (repo2) {
47488
+ if (item.slug === repo2) {
47489
+ return true;
47490
+ }
47491
+ } else {
47492
+ if (item.slug.includes("/dev")) {
47493
+ return true;
47494
+ }
47495
+ }
47496
+ return false;
47497
+ });
47498
+ for (const item of _list) {
47499
+ const branch = item.branch || "main";
47500
+ const repo3 = item.slug;
47501
+ const sn = item.sn;
47502
+ await cnb.workspace.stopWorkspace({ sn });
47503
+ if (config3) {
47504
+ await cnb.build.startBuild(repo3, { branch, config: config3, event });
47505
+ } else {
47506
+ await cnb.workspace.startWorkspace(repo3, { branch });
47507
+ }
47508
+ }
47509
+ ctx.body = {
47510
+ content: "工作区重新启动中"
47511
+ };
47512
+ }).addTo(app);
47513
+
47456
47514
  // agent/routes/workspace/index.ts
47457
47515
  app.route({
47458
47516
  path: "cnb",
@@ -48437,8 +48495,8 @@ app.route({
48437
48495
  const cnb = await cnbManager.getContext(ctx);
48438
48496
  let repo2 = ctx.query?.repo || useKey("CNB_REPO_SLUG_LOWERCASE");
48439
48497
  const issueNumber = ctx.query?.issueNumber;
48440
- const page = ctx.query?.page ? Number(ctx.query.page) : undefined;
48441
- const page_size = ctx.query?.page_size ? Number(ctx.query.page_size) : undefined;
48498
+ const page = ctx.query?.page ?? 1;
48499
+ const page_size = ctx.query?.page_size ?? 100;
48442
48500
  if (!repo2) {
48443
48501
  ctx.throw(400, "缺少参数 repo");
48444
48502
  }
@@ -55447,6 +55505,180 @@ app.route({
55447
55505
  ctx.forward(res);
55448
55506
  }).addTo(app);
55449
55507
 
55508
+ // agent/routes/labels/issue-label.ts
55509
+ app.route({
55510
+ path: "cnb",
55511
+ key: "list-issue-labels",
55512
+ description: "查询 Issue 的标签列表",
55513
+ middleware: ["auth"],
55514
+ metadata: {
55515
+ tags: ["opencode"],
55516
+ ...createSkill({
55517
+ skill: "list-issue-labels",
55518
+ title: "查询 Issue 标签列表",
55519
+ summary: "查询 Issue 的标签列表",
55520
+ args: {
55521
+ repo: tool.schema.string().optional().describe("仓库路径, 如 my-user/my-repo"),
55522
+ issueNumber: tool.schema.number().describe("Issue 编号"),
55523
+ page: tool.schema.number().optional().describe("分页页码,默认 1"),
55524
+ pageSize: tool.schema.number().optional().describe("分页每页大小,默认 30")
55525
+ }
55526
+ })
55527
+ }
55528
+ }).define(async (ctx) => {
55529
+ const cnb = await cnbManager.getContext(ctx);
55530
+ let repo2 = ctx.query?.repo || useKey("CNB_REPO_SLUG_LOWERCASE");
55531
+ const issueNumber = ctx.query?.issueNumber;
55532
+ const page = ctx.query?.page;
55533
+ const pageSize = ctx.query?.pageSize;
55534
+ if (!repo2) {
55535
+ ctx.throw(400, "缺少参数 repo");
55536
+ }
55537
+ if (!issueNumber) {
55538
+ ctx.throw(400, "缺少参数 issueNumber");
55539
+ }
55540
+ const res = await cnb.labels.issueLabel.list(repo2, issueNumber, {
55541
+ page,
55542
+ page_size: pageSize
55543
+ });
55544
+ ctx.forward(res);
55545
+ }).addTo(app);
55546
+ app.route({
55547
+ path: "cnb",
55548
+ key: "set-issue-labels",
55549
+ description: "设置 Issue 标签(完全替换现有标签)",
55550
+ middleware: ["auth"],
55551
+ metadata: {
55552
+ tags: ["opencode"],
55553
+ ...createSkill({
55554
+ skill: "set-issue-labels",
55555
+ title: "设置 Issue 标签",
55556
+ summary: "设置 Issue 标签(完全替换现有标签)",
55557
+ args: {
55558
+ repo: tool.schema.string().optional().describe("仓库路径, 如 my-user/my-repo"),
55559
+ issueNumber: tool.schema.number().describe("Issue 编号"),
55560
+ labels: tool.schema.array(tool.schema.string()).describe("标签名称数组")
55561
+ }
55562
+ })
55563
+ }
55564
+ }).define(async (ctx) => {
55565
+ const cnb = await cnbManager.getContext(ctx);
55566
+ let repo2 = ctx.query?.repo || useKey("CNB_REPO_SLUG_LOWERCASE");
55567
+ const issueNumber = ctx.query?.issueNumber;
55568
+ const labels2 = ctx.query?.labels;
55569
+ if (!repo2) {
55570
+ ctx.throw(400, "缺少参数 repo");
55571
+ }
55572
+ if (!issueNumber) {
55573
+ ctx.throw(400, "缺少参数 issueNumber");
55574
+ }
55575
+ if (!labels2 || !Array.isArray(labels2)) {
55576
+ ctx.throw(400, "缺少参数 labels");
55577
+ }
55578
+ const res = await cnb.labels.issueLabel.set(repo2, issueNumber, { labels: labels2 });
55579
+ ctx.forward(res);
55580
+ }).addTo(app);
55581
+ app.route({
55582
+ path: "cnb",
55583
+ key: "add-issue-labels",
55584
+ description: "新增 Issue 标签(追加到现有标签)",
55585
+ middleware: ["auth"],
55586
+ metadata: {
55587
+ tags: ["opencode"],
55588
+ ...createSkill({
55589
+ skill: "add-issue-labels",
55590
+ title: "新增 Issue 标签",
55591
+ summary: "新增 Issue 标签(追加到现有标签)",
55592
+ args: {
55593
+ repo: tool.schema.string().optional().describe("仓库路径, 如 my-user/my-repo"),
55594
+ issueNumber: tool.schema.number().describe("Issue 编号"),
55595
+ labels: tool.schema.array(tool.schema.string()).describe("标签名称数组")
55596
+ }
55597
+ })
55598
+ }
55599
+ }).define(async (ctx) => {
55600
+ const cnb = await cnbManager.getContext(ctx);
55601
+ let repo2 = ctx.query?.repo || useKey("CNB_REPO_SLUG_LOWERCASE");
55602
+ const issueNumber = ctx.query?.issueNumber;
55603
+ const labels2 = ctx.query?.labels;
55604
+ if (!repo2) {
55605
+ ctx.throw(400, "缺少参数 repo");
55606
+ }
55607
+ if (!issueNumber) {
55608
+ ctx.throw(400, "缺少参数 issueNumber");
55609
+ }
55610
+ if (!labels2 || !Array.isArray(labels2)) {
55611
+ ctx.throw(400, "缺少参数 labels");
55612
+ }
55613
+ const res = await cnb.labels.issueLabel.add(repo2, issueNumber, { labels: labels2 });
55614
+ ctx.forward(res);
55615
+ }).addTo(app);
55616
+ app.route({
55617
+ path: "cnb",
55618
+ key: "clear-issue-labels",
55619
+ description: "清空 Issue 标签(移除所有标签)",
55620
+ middleware: ["auth"],
55621
+ metadata: {
55622
+ tags: ["opencode"],
55623
+ ...createSkill({
55624
+ skill: "clear-issue-labels",
55625
+ title: "清空 Issue 标签",
55626
+ summary: "清空 Issue 标签(移除所有标签)",
55627
+ args: {
55628
+ repo: tool.schema.string().optional().describe("仓库路径, 如 my-user/my-repo"),
55629
+ issueNumber: tool.schema.number().describe("Issue 编号")
55630
+ }
55631
+ })
55632
+ }
55633
+ }).define(async (ctx) => {
55634
+ const cnb = await cnbManager.getContext(ctx);
55635
+ let repo2 = ctx.query?.repo || useKey("CNB_REPO_SLUG_LOWERCASE");
55636
+ const issueNumber = ctx.query?.issueNumber;
55637
+ if (!repo2) {
55638
+ ctx.throw(400, "缺少参数 repo");
55639
+ }
55640
+ if (!issueNumber) {
55641
+ ctx.throw(400, "缺少参数 issueNumber");
55642
+ }
55643
+ const res = await cnb.labels.issueLabel.clear(repo2, issueNumber);
55644
+ ctx.forward(res);
55645
+ }).addTo(app);
55646
+ app.route({
55647
+ path: "cnb",
55648
+ key: "remove-issue-label",
55649
+ description: "删除 Issue 指定标签",
55650
+ middleware: ["auth"],
55651
+ metadata: {
55652
+ tags: ["opencode"],
55653
+ ...createSkill({
55654
+ skill: "remove-issue-label",
55655
+ title: "删除 Issue 标签",
55656
+ summary: "删除 Issue 指定标签",
55657
+ args: {
55658
+ repo: tool.schema.string().optional().describe("仓库路径, 如 my-user/my-repo"),
55659
+ issueNumber: tool.schema.number().describe("Issue 编号"),
55660
+ name: tool.schema.string().describe("标签名称")
55661
+ }
55662
+ })
55663
+ }
55664
+ }).define(async (ctx) => {
55665
+ const cnb = await cnbManager.getContext(ctx);
55666
+ let repo2 = ctx.query?.repo || useKey("CNB_REPO_SLUG_LOWERCASE");
55667
+ const issueNumber = ctx.query?.issueNumber;
55668
+ const name21 = ctx.query?.name;
55669
+ if (!repo2) {
55670
+ ctx.throw(400, "缺少参数 repo");
55671
+ }
55672
+ if (!issueNumber) {
55673
+ ctx.throw(400, "缺少参数 issueNumber");
55674
+ }
55675
+ if (!name21) {
55676
+ ctx.throw(400, "缺少参数 name");
55677
+ }
55678
+ const res = await cnb.labels.issueLabel.remove(repo2, issueNumber, name21);
55679
+ ctx.forward(res);
55680
+ }).addTo(app);
55681
+
55450
55682
  // agent/routes/index.ts
55451
55683
  var checkAppId = (ctx, appId) => {
55452
55684
  const _appId = ctx?.app?.appId;
@@ -55498,7 +55730,7 @@ var {
55498
55730
  Help
55499
55731
  } = import__3.default;
55500
55732
 
55501
- // ../../node_modules/.pnpm/@kevisual+remote-app@0.0.6/node_modules/@kevisual/remote-app/dist/app.js
55733
+ // ../../node_modules/.pnpm/@kevisual+remote-app@0.0.7/node_modules/@kevisual/remote-app/dist/app.js
55502
55734
  var __create4 = Object.create;
55503
55735
  var __getProtoOf4 = Object.getPrototypeOf;
55504
55736
  var __defProp5 = Object.defineProperty;
@@ -55713,10 +55945,12 @@ class RemoteApp {
55713
55945
  reconnectAttempts = 0;
55714
55946
  reconnectTimer = null;
55715
55947
  isManuallyClosed = false;
55948
+ isInitializing = false;
55949
+ initId = 0;
55716
55950
  constructor(opts) {
55717
55951
  this.mainApp = opts?.app;
55718
55952
  const token2 = opts.token;
55719
- const url4 = opts.url;
55953
+ const url4 = opts.url || "https://kevisual.cn/ws/proxy";
55720
55954
  const id = opts.id;
55721
55955
  const username = opts.username;
55722
55956
  this.username = username;
@@ -55782,10 +56016,17 @@ class RemoteApp {
55782
56016
  return wsURL;
55783
56017
  }
55784
56018
  async init() {
56019
+ if (this.isInitializing) {
56020
+ return;
56021
+ }
56022
+ this.isInitializing = true;
56023
+ const currentInitId = ++this.initId;
55785
56024
  if (!this.url) {
56025
+ this.isInitializing = false;
55786
56026
  throw new Error("No url provided for remote app");
55787
56027
  }
55788
56028
  if (!this.id) {
56029
+ this.isInitializing = false;
55789
56030
  throw new Error("No id provided for remote app");
55790
56031
  }
55791
56032
  this.isError = false;
@@ -55795,11 +56036,20 @@ class RemoteApp {
55795
56036
  const ws = new WebSocket(this.getWsURL(this.url));
55796
56037
  const that = this;
55797
56038
  ws.onopen = function() {
56039
+ if (currentInitId !== that.initId) {
56040
+ ws.close();
56041
+ return;
56042
+ }
55798
56043
  that.isConnected = true;
56044
+ that.isInitializing = false;
55799
56045
  that.onOpen();
55800
56046
  console.log("[remote-app] WebSocket connection opened");
55801
56047
  };
55802
56048
  ws.onclose = function() {
56049
+ if (currentInitId !== that.initId) {
56050
+ return;
56051
+ }
56052
+ that.isInitializing = false;
55803
56053
  that.isConnected = false;
55804
56054
  that.onClose();
55805
56055
  };
@@ -55807,6 +56057,10 @@ class RemoteApp {
55807
56057
  that.onMessage(event.data);
55808
56058
  };
55809
56059
  ws.onerror = function(error49) {
56060
+ if (currentInitId !== that.initId) {
56061
+ return;
56062
+ }
56063
+ that.isInitializing = false;
55810
56064
  that.onError(error49);
55811
56065
  };
55812
56066
  this.ws = ws;
@@ -56201,9 +56455,9 @@ var writeToProcess = (message) => {
56201
56455
  var getIssuesLabels = async () => {
56202
56456
  const issueEnv = useIssueEnv();
56203
56457
  const repoInfoEnv = useRepoInfoEnv();
56204
- const issueId = issueEnv.issueId;
56458
+ const issueIid = issueEnv.issueIid;
56205
56459
  const repoSlug = repoInfoEnv.repoSlug;
56206
- if (!issueId || !repoSlug) {
56460
+ if (!issueIid || !repoSlug) {
56207
56461
  return [];
56208
56462
  }
56209
56463
  const res = await app.run({
@@ -56211,7 +56465,7 @@ var getIssuesLabels = async () => {
56211
56465
  key: "getIssue",
56212
56466
  payload: {
56213
56467
  repo: repoSlug,
56214
- issueNumber: issueId
56468
+ issueNumber: issueIid
56215
56469
  }
56216
56470
  });
56217
56471
  if (res.code === 200) {
@@ -56222,12 +56476,32 @@ var getIssuesLabels = async () => {
56222
56476
  console.error("获取 Issue 详情失败", res);
56223
56477
  return [];
56224
56478
  };
56225
- var main = async ({ exit, question }) => {
56479
+ var getIssueComment = async (opts) => {
56480
+ const res = await app.run({
56481
+ path: "cnb",
56482
+ key: "list-issue-comments",
56483
+ payload: {
56484
+ repo: opts.repo,
56485
+ issueNumber: opts.issueNumber
56486
+ }
56487
+ });
56488
+ let comments = [];
56489
+ if (res.code === 200) {
56490
+ const data = res.data;
56491
+ comments = data.map((item) => ({
56492
+ commentId: item.id,
56493
+ body: item.body,
56494
+ author: item.author?.nickname || item.author?.username || "unknown"
56495
+ }));
56496
+ }
56497
+ return comments;
56498
+ };
56499
+ var main = async ({ exit, question, admins }) => {
56226
56500
  const repoInfoEnv = useRepoInfoEnv();
56227
56501
  const commentEnv = useCommentEnv();
56228
56502
  const issueEnv = useIssueEnv();
56229
56503
  const pickCommentEnv = pick4(commentEnv, ["commentId", "commentIdLabel"]);
56230
- const pickIssueEnv = pick4(issueEnv, ["issueId", "issueIdLabel", "issueIid", "issueIidLabel", "issueTitle", "issueTitleLabel", "issueDescription", "issueDescriptionLabel"]);
56504
+ const pickIssueEnv = pick4(issueEnv, ["issueIid", "issueIidLabel", "issueTitle", "issueTitleLabel", "issueDescription", "issueDescriptionLabel"]);
56231
56505
  const pickRepoInfoEnv = pick4(repoInfoEnv, ["repoId", "repoIdLabel", "repoName", "repoNameLabel", "repoSlug", "repoSlugLabel"]);
56232
56506
  const isComment = !!commentEnv.commentId;
56233
56507
  const envList = [
@@ -56243,15 +56517,41 @@ var main = async ({ exit, question }) => {
56243
56517
  writeToProcess("当前 Issue 不包含 Run 标签,跳过执行");
56244
56518
  return exit(0);
56245
56519
  }
56520
+ const issueComments = await getIssueComment({ repo: repoInfoEnv.repoSlug || "", issueNumber: Number(issueEnv.issueIid) });
56521
+ if (issueComments.length > 0) {
56522
+ const lastComment = issueComments[issueComments.length - 1];
56523
+ if (admins.length > 0 && !admins.includes(lastComment.author)) {
56524
+ writeToProcess(`当前 Issue 最新的评论由 ${lastComment.author} 创建,不是管理员 ${admins.join(", ")},跳过执行`);
56525
+ const helperKey = ["帮", "做", "执行", "处理", "解决", "回复", "评论"];
56526
+ const hasHelper = helperKey.some((key) => question?.includes(key));
56527
+ if (!hasHelper) {
56528
+ await app.run({
56529
+ path: "cnb",
56530
+ key: "create-issue-comment",
56531
+ payload: {
56532
+ repo: repoInfoEnv.repoSlug || "",
56533
+ issueNumber: Number(issueEnv.issueIid),
56534
+ body: `当前 Issue 最新的评论由 ${lastComment.author} 创建,不是管理员,不允许执行喵~`
56535
+ }
56536
+ });
56537
+ }
56538
+ return exit(0);
56539
+ }
56540
+ }
56541
+ const botName = "kevisual/cnb(router) ";
56246
56542
  const messages = [
56247
56543
  {
56248
56544
  role: "system",
56249
- content: `你是一个智能的代码助手, 根据用户提供的上下文信息,提供有用的建议和帮助, 如果用户的要求和执行工具不一致,请说出你不能这么做。并把最后的结果提交一个评论到对应的issue中,提交的内容必须不能包含 @ 提及。用户提供的上下文信息如下:`
56545
+ content: `你是一个智能的代码助手叫${botName}, 根据用户提供的上下文信息,提供有用的建议和帮助, 如果用户的要求和执行工具不一致,请说出你不能这么做。并把最后的结果提交一个评论到对应的issue中,提交的内容必须不能包含 @ 提及。如果你有些决定不能决定,需要咨询,需要任何交互的,也把对应的需求评论到对应的issue。用户提供的上下文信息如下:`
56250
56546
  },
56251
56547
  {
56252
56548
  role: "system",
56253
56549
  content: `相关变量:${JSON.stringify({ ...pickCommentEnv, ...pickIssueEnv, ...pickRepoInfoEnv })}`
56254
56550
  },
56551
+ {
56552
+ role: "assistant",
56553
+ content: "历史评论:" + JSON.stringify(issueComments)
56554
+ },
56255
56555
  {
56256
56556
  role: "user",
56257
56557
  content: question || commentEnv.commentBody || pickIssueEnv.issueDescription || "无"
@@ -56298,9 +56598,9 @@ app.route({
56298
56598
  const buildUserNickName = useKey("CNB_BUILD_USER_NICKNAME");
56299
56599
  let admins = owner.split(",").map((item) => item.trim());
56300
56600
  if (owner && admins.includes(buildUserNickName)) {
56301
- await main({ exit });
56601
+ await main({ exit, admins });
56302
56602
  } else {
56303
- await main({ exit, question: `你是${owner}的专属助手,请生成一条评论,说明你不具备其他用户能访问的能力。同时你需要提示说明,fork当前仓库后,即可成为你的专属助手` });
56603
+ await main({ exit, admins, question: `你是${owner}的专属助手,请生成一条评论,说明你不具备其他用户能访问的能力。同时你需要提示说明,fork当前仓库后,即可成为你的专属助手` });
56304
56604
  }
56305
56605
  }).addTo(app);
56306
56606
  parse8({ app, description: "CNB控制台命令行工具", parse: true });