@kevisual/cli 0.1.10 → 0.1.12

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.
@@ -44002,6 +44002,7 @@ class AssistantConfig {
44002
44002
  }
44003
44003
  getDefaultInitAssistantConfig() {
44004
44004
  const id = randomId2();
44005
+ const isCNB = !!useKey("CNB");
44005
44006
  return {
44006
44007
  app: {
44007
44008
  url: "https://kevisual.cn",
@@ -44009,7 +44010,7 @@ class AssistantConfig {
44009
44010
  },
44010
44011
  description: "助手配置文件",
44011
44012
  docs: "https://kevisual.cn/root/cli/docs/",
44012
- home: "/root/home",
44013
+ home: isCNB ? "/root/cli-center" : "/root/home",
44013
44014
  proxy: [],
44014
44015
  share: {
44015
44016
  enabled: true,
@@ -100298,11 +100299,11 @@ app.route({
100298
100299
  })
100299
100300
  }
100300
100301
  }).define(async (ctx) => {
100301
- const { path: path14, key = "" } = ctx.query;
100302
+ const { path: path14, key = "" } = ctx.args;
100302
100303
  if (!path14) {
100303
100304
  ctx.throw("路径path不能为空");
100304
100305
  }
100305
- const res = await ctx.run({ path: path14, key, payload: ctx.query.payload || {} }, {
100306
+ const res = await ctx.run({ path: path14, key, payload: ctx.args.payload || {} }, {
100306
100307
  ...ctx
100307
100308
  });
100308
100309
  ctx.forward(res);
@@ -102169,20 +102170,22 @@ app.route({
102169
102170
  // src/routes/cnb-board/live/live-content.ts
102170
102171
  var import_dayjs = __toESM(require_dayjs_min(), 1);
102171
102172
  import os7 from "node:os";
102173
+ import { execSync as execSync3 } from "node:child_process";
102172
102174
  var getLiveMdContent = (opts) => {
102173
102175
  const more = opts?.more ?? false;
102174
102176
  const url4 = useKey2("CNB_VSCODE_PROXY_URI") || "";
102175
102177
  const token = useKey2("CNB_TOKEN") || "";
102176
102178
  const openclawPort = useKey2("OPENCLAW_PORT") || "80";
102177
- const openclawUrl = url4?.replace("{{port}}", openclawPort);
102179
+ const openclawUrl = url4.replace("{{port}}", openclawPort);
102178
102180
  const openclawUrlSecret = openclawUrl + "/openclaw?token=" + token;
102179
102181
  const opencodePort = useKey2("OPENCODE_PORT") || "100";
102180
- const opencodeUrl = url4?.replace("{{port}}", opencodePort);
102182
+ const opencodeUrl = url4.replace("{{port}}", opencodePort);
102181
102183
  const _opencodeURL = new URL(opencodeUrl);
102182
102184
  _opencodeURL.username = "root";
102183
102185
  _opencodeURL.password = token;
102184
102186
  const opencodeUrlSecret = _opencodeURL.toString();
102185
- const kevisualUrl = url4?.replace("{{port}}", "51515");
102187
+ const kevisualUrl = url4.replace("{{port}}", "51515");
102188
+ const openWebUrl = url4.replace("{{port}}", "200");
102186
102189
  const vscodeWebUrl = useKey2("CNB_VSCODE_WEB_URL") || "";
102187
102190
  const TEMPLATE = `# 开发环境模式配置
102188
102191
 
@@ -102190,6 +102193,9 @@ var getLiveMdContent = (opts) => {
102190
102193
  #### nginx 反向代理访问(推荐)
102191
102194
  - OpenClaw: ${openclawUrl + "/openclaw"}
102192
102195
  - OpenCode: ${opencodeUrl}
102196
+ - VSCode Web: ${vscodeWebUrl}
102197
+ - OpenWebUI: ${openWebUrl}
102198
+ - Kevisual: ${kevisualUrl}
102193
102199
 
102194
102200
  ### 直接访问
102195
102201
  - Kevisual: ${kevisualUrl}
@@ -102213,47 +102219,61 @@ var getLiveMdContent = (opts) => {
102213
102219
  - wss: vscode web的websocket地址
102214
102220
  - cookie: vscode web的cookie,保持和浏览器一致
102215
102221
  - url: vscode web的访问地址,可以直接访问vscode web
102216
- 4. 运行cli命令,ev cnb live -c /workspace/live/keep.json
102222
+ 4. 运行cli命令,ev cnb live -c /workspace/live/keep.json.(直接对话opencode或者openclaw调用cnb-live技能即可)
102217
102223
 
102218
102224
  `;
102219
102225
  const labels = [
102220
102226
  {
102221
- title: "vscodeWebUrl",
102227
+ key: "vscodeWebUrl",
102228
+ title: "VSCode Web 地址",
102222
102229
  value: vscodeWebUrl,
102223
102230
  description: "VSCode Web 的访问地址"
102224
102231
  },
102225
102232
  {
102226
- title: "kevisualUrl",
102233
+ key: "kevisualUrl",
102234
+ title: "Kevisual 地址",
102227
102235
  value: kevisualUrl,
102228
102236
  description: "Kevisual 的访问地址,可以通过该地址访问 Kevisual 服务"
102229
102237
  },
102230
102238
  {
102231
- title: "cnbTempToken",
102239
+ key: "cnbTempToken",
102240
+ title: "CNB Token",
102232
102241
  value: token,
102233
102242
  description: "CNB 临时 Token,保持和环境变量 CNB_TOKEN 一致"
102234
102243
  },
102235
102244
  {
102236
- title: "openclawUrl",
102245
+ key: "openWebUrl",
102246
+ title: "OpenWebUI 地址",
102247
+ value: openWebUrl,
102248
+ description: "OpenWebUI 的访问地址,可以通过该地址访问 OpenWebUI 服务"
102249
+ },
102250
+ {
102251
+ key: "openclawUrl",
102252
+ title: "OpenClaw 地址",
102237
102253
  value: openclawUrl,
102238
102254
  description: "OpenClaw 的访问地址,可以通过该地址访问 OpenClaw 服务"
102239
102255
  },
102240
102256
  {
102241
- title: "openclawUrlSecret",
102257
+ key: "openclawUrlSecret",
102258
+ title: "OpenClaw 访问地址(含 Token)",
102242
102259
  value: openclawUrlSecret,
102243
102260
  description: "OpenClaw 的访问地址,包含 token 参数,可以直接访问 OpenClaw 服务"
102244
102261
  },
102245
102262
  {
102246
- title: "opencodeUrl",
102263
+ key: "opencodeUrl",
102264
+ title: "OpenCode 地址",
102247
102265
  value: opencodeUrl,
102248
102266
  description: "OpenCode 的访问地址,可以通过该地址访问 OpenCode 服务"
102249
102267
  },
102250
102268
  {
102251
- title: "opencodeUrlSecret",
102269
+ key: "opencodeUrlSecret",
102270
+ title: "OpenCode 访问地址(含 Token)",
102252
102271
  value: opencodeUrlSecret,
102253
102272
  description: "OpenCode 的访问地址,包含 token 参数,可以直接访问 OpenCode 服务"
102254
102273
  },
102255
102274
  {
102256
- title: "docs",
102275
+ key: "docs",
102276
+ title: "配置说明文档",
102257
102277
  value: TEMPLATE,
102258
102278
  description: "开发环境模式配置说明文档"
102259
102279
  }
@@ -102264,7 +102284,7 @@ var getLiveMdContent = (opts) => {
102264
102284
  };
102265
102285
  var createOSInfo = (more = false) => {
102266
102286
  const labels = [];
102267
- const startTimer = useKey2("CNB_BUILD_START_TIME") || 0;
102287
+ const startTimer = useKey2("CNB_BUILD_START_TIME") || "";
102268
102288
  const cpus = os7.cpus();
102269
102289
  let totalIdle = 0;
102270
102290
  let totalTick = 0;
@@ -102275,10 +102295,26 @@ var createOSInfo = (more = false) => {
102275
102295
  totalIdle += cpu.times.idle;
102276
102296
  });
102277
102297
  const cpuUsage = ((1 - totalIdle / totalTick) * 100).toFixed(2);
102278
- const totalMem = os7.totalmem();
102279
- const freeMem = os7.freemem();
102280
- const usedMem = totalMem - freeMem;
102281
- const memUsage = (usedMem / totalMem * 100).toFixed(2);
102298
+ let memUsed = 0;
102299
+ let memTotal = 0;
102300
+ let memFree = 0;
102301
+ try {
102302
+ const freeOutput = execSync3("free -b", { encoding: "utf-8" });
102303
+ const lines = freeOutput.trim().split(`
102304
+ `);
102305
+ const memLine = lines.find((line) => line.startsWith("Mem:"));
102306
+ if (memLine) {
102307
+ const parts = memLine.split(/\s+/);
102308
+ memTotal = parseInt(parts[1]);
102309
+ memUsed = parseInt(parts[2]);
102310
+ memFree = parseInt(parts[3]);
102311
+ }
102312
+ } catch (e) {
102313
+ memTotal = os7.totalmem();
102314
+ memFree = os7.freemem();
102315
+ memUsed = memTotal - memFree;
102316
+ }
102317
+ const memUsage = memTotal > 0 ? (memUsed / memTotal * 100).toFixed(2) : "0.00";
102282
102318
  const formatBytes = (bytes) => {
102283
102319
  const sizes = ["B", "KB", "MB", "GB", "TB"];
102284
102320
  if (bytes === 0)
@@ -102286,92 +102322,137 @@ var createOSInfo = (more = false) => {
102286
102322
  const i = Math.floor(Math.log(bytes) / Math.log(1024));
102287
102323
  return (bytes / Math.pow(1024, i)).toFixed(2) + " " + sizes[i];
102288
102324
  };
102289
- const bootTime = os7.uptime();
102290
- const bootTimeDate = new Date(Date.now() - bootTime * 1000);
102291
- const bootTimeStr = import_dayjs.default(bootTimeDate).format("YYYY-MM-DD HH:mm:ss");
102292
102325
  const formatUptime = (seconds) => {
102293
102326
  const days = Math.floor(seconds / 86400);
102294
102327
  const hours = Math.floor(seconds % 86400 / 3600);
102295
102328
  const minutes = Math.floor(seconds % 3600 / 60);
102296
102329
  const secs = Math.floor(seconds % 60);
102297
- return `${days}天 ${hours}小时 ${minutes}分钟 ${secs}秒`;
102298
- };
102299
- const diskInfo = "可通过 df -h 命令获取";
102330
+ let uptimeStr = "";
102331
+ if (days > 0)
102332
+ uptimeStr += `${days}天 `;
102333
+ if (hours > 0)
102334
+ uptimeStr += `${hours}小时 `;
102335
+ if (minutes > 0)
102336
+ uptimeStr += `${minutes}分钟 `;
102337
+ return `${uptimeStr}${secs}秒`;
102338
+ };
102339
+ let diskUsage = "";
102340
+ try {
102341
+ const duOutput = execSync3("du -sh .", { encoding: "utf-8" });
102342
+ diskUsage = duOutput.trim().split("\t")[0];
102343
+ } catch (e) {
102344
+ diskUsage = "获取失败";
102345
+ }
102300
102346
  labels.push({
102301
- title: "cpuUsage",
102347
+ key: "cpuUsage",
102348
+ title: "CPU 使用率",
102302
102349
  value: `${cpuUsage}%`,
102303
102350
  description: "CPU 使用率"
102304
102351
  }, {
102305
- title: "cpuCores",
102352
+ key: "cpuCores",
102353
+ title: "CPU 核心数",
102306
102354
  value: `${cpus.length}`,
102307
102355
  description: "CPU 核心数"
102308
102356
  }, {
102309
- title: "memoryUsed",
102310
- value: formatBytes(usedMem),
102357
+ key: "memoryUsed",
102358
+ title: "已使用内存",
102359
+ value: formatBytes(memUsed),
102311
102360
  description: "已使用内存"
102312
102361
  }, {
102313
- title: "memoryTotal",
102314
- value: formatBytes(totalMem),
102362
+ key: "memoryTotal",
102363
+ title: "总内存",
102364
+ value: formatBytes(memTotal),
102315
102365
  description: "总内存"
102316
102366
  }, {
102317
- title: "memoryUsage",
102367
+ key: "memoryFree",
102368
+ title: "空闲内存",
102369
+ value: formatBytes(memFree),
102370
+ description: "空闲内存"
102371
+ }, {
102372
+ key: "memoryUsage",
102373
+ title: "内存使用率",
102318
102374
  value: `${memUsage}%`,
102319
102375
  description: "内存使用率"
102320
102376
  }, {
102321
- title: "diskInfo",
102322
- value: diskInfo,
102323
- description: "磁盘信息 (请使用 df -h 命令查看)"
102324
- }, {
102325
- title: "bootTime",
102326
- value: bootTimeStr,
102327
- description: "系统启动时间"
102328
- }, {
102329
- title: "uptime",
102330
- value: formatUptime(bootTime),
102331
- description: "系统运行时间"
102377
+ key: "diskUsage",
102378
+ title: "磁盘使用",
102379
+ value: diskUsage,
102380
+ description: "当前目录磁盘使用情况"
102332
102381
  });
102333
102382
  if (startTimer) {
102334
- const buildStartTime = import_dayjs.default(parseInt(startTimer)).format("YYYY-MM-DD HH:mm:ss");
102335
- const buildUptime = Date.now() - parseInt(startTimer);
102383
+ const buildStartTime = import_dayjs.default(startTimer).format("YYYY-MM-DD HH:mm:ss");
102384
+ const buildStartTimestamp = import_dayjs.default(startTimer).valueOf();
102385
+ const buildUptime = Date.now() - buildStartTimestamp;
102336
102386
  const buildUptimeStr = formatUptime(Math.floor(buildUptime / 1000));
102387
+ const maxRunTime = useKey2("CNB_PIPELINE_MAX_RUN_TIME") || 0;
102337
102388
  labels.push({
102338
- title: "buildStartTime",
102389
+ key: "buildStartTime",
102390
+ title: "构建启动时间",
102339
102391
  value: buildStartTime,
102340
102392
  description: "构建启动时间"
102341
102393
  }, {
102342
- title: "buildUptime",
102394
+ key: "buildUptime",
102395
+ title: "构建已运行时间",
102343
102396
  value: buildUptimeStr,
102344
102397
  description: "构建已运行时间"
102345
102398
  });
102399
+ if (maxRunTime > 0) {
102400
+ const now = import_dayjs.default();
102401
+ const today4am = now.hour(4).minute(0).second(0).millisecond(0);
102402
+ let timeTo4 = today4am.valueOf() - now.valueOf();
102403
+ if (timeTo4 < 0) {
102404
+ timeTo4 = today4am.add(1, "day").valueOf() - now.valueOf();
102405
+ }
102406
+ const timeTo4Str = `[距离晚上4点重启时间: ${formatUptime(Math.floor(timeTo4 / 1000))}]`;
102407
+ labels.push({
102408
+ key: "buildMaxRunTime",
102409
+ title: "最大运行时间",
102410
+ value: formatUptime(Math.floor(maxRunTime / 1000)),
102411
+ description: "构建最大运行时间(限制时间)"
102412
+ });
102413
+ labels.unshift({
102414
+ key: "remainingTime",
102415
+ title: "剩余时间",
102416
+ value: formatUptime(Math.floor((maxRunTime - buildUptime) / 1000)) + " " + timeTo4Str,
102417
+ description: "构建剩余时间"
102418
+ });
102419
+ }
102346
102420
  }
102347
102421
  if (more) {
102348
102422
  const loadavg = os7.loadavg();
102349
102423
  labels.push({
102350
- title: "hostname",
102424
+ key: "hostname",
102425
+ title: "主机名",
102351
102426
  value: os7.hostname(),
102352
102427
  description: "主机名"
102353
102428
  }, {
102354
- title: "platform",
102429
+ key: "platform",
102430
+ title: "运行平台",
102355
102431
  value: os7.platform(),
102356
102432
  description: "运行平台"
102357
102433
  }, {
102358
- title: "arch",
102434
+ key: "arch",
102435
+ title: "系统架构",
102359
102436
  value: os7.arch(),
102360
102437
  description: "系统架构"
102361
102438
  }, {
102362
- title: "osType",
102439
+ key: "osType",
102440
+ title: "操作系统类型",
102363
102441
  value: os7.type(),
102364
102442
  description: "操作系统类型"
102365
102443
  }, {
102366
- title: "loadavg1m",
102444
+ key: "loadavg1m",
102445
+ title: "系统负载 (1分钟)",
102367
102446
  value: loadavg[0].toFixed(2),
102368
102447
  description: "系统负载 (1分钟)"
102369
102448
  }, {
102370
- title: "loadavg5m",
102449
+ key: "loadavg5m",
102450
+ title: "系统负载 (5分钟)",
102371
102451
  value: loadavg[1].toFixed(2),
102372
102452
  description: "系统负载 (5分钟)"
102373
102453
  }, {
102374
- title: "loadavg15m",
102454
+ key: "loadavg15m",
102455
+ title: "系统负载 (15分钟)",
102375
102456
  value: loadavg[2].toFixed(2),
102376
102457
  description: "系统负载 (15分钟)"
102377
102458
  });
@@ -102380,16 +102461,49 @@ var createOSInfo = (more = false) => {
102380
102461
  };
102381
102462
 
102382
102463
  // src/routes/cnb-board/cnb-dev-env.ts
102464
+ var notCNBCheck = (ctx) => {
102465
+ const isCNB = useKey2("CNB");
102466
+ if (!isCNB) {
102467
+ ctx.body = {
102468
+ title: "非 cnb-board 环境",
102469
+ list: []
102470
+ };
102471
+ return true;
102472
+ }
102473
+ return false;
102474
+ };
102383
102475
  app.route({
102384
- path: "cnb-board",
102385
- key: "live-repo-info",
102476
+ path: "cnb_board",
102477
+ key: "live",
102478
+ description: "获取cnb-board live的mdContent内容",
102479
+ middleware: ["auth-admin"],
102480
+ metadata: {
102481
+ args: {
102482
+ more: zod_default.boolean().optional().describe("是否获取更多系统信息,默认false")
102483
+ }
102484
+ }
102485
+ }).define(async (ctx) => {
102486
+ const more = ctx.query?.more ?? false;
102487
+ const list4 = getLiveMdContent({ more });
102488
+ if (notCNBCheck(ctx))
102489
+ return;
102490
+ ctx.body = {
102491
+ title: "开发环境模式配置",
102492
+ list: list4
102493
+ };
102494
+ }).addTo(app);
102495
+ app.route({
102496
+ path: "cnb_board",
102497
+ key: "live_repo_info",
102386
102498
  description: "获取cnb-board live的repo信息",
102387
102499
  middleware: ["auth-admin"]
102388
102500
  }).define(async (ctx) => {
102389
102501
  const repoSlug = useKey2("CNB_REPO_SLUG") || "";
102390
102502
  const repoName = useKey2("CNB_REPO_NAME") || "";
102391
102503
  const repoId = useKey2("CNB_REPO_ID") || "";
102392
- const repoUrlHttps = useKey2("CNB_REPO_URL_HTTPS") || "";
102504
+ const repoUrlHttps = useKey2("CNB_REPO_UR if (notCNBCheck(ctx)) return;L_HTTPS") || "";
102505
+ if (notCNBCheck(ctx))
102506
+ return;
102393
102507
  const repoNameFromSlug = repoSlug.split("/").pop() || "";
102394
102508
  const labels = [
102395
102509
  {
@@ -102429,11 +102543,13 @@ app.route({
102429
102543
  };
102430
102544
  }).addTo(app);
102431
102545
  app.route({
102432
- path: "cnb-board",
102433
- key: "live-build-info",
102546
+ path: "cnb_board",
102547
+ key: "live_build_info",
102434
102548
  description: "获取cnb-board live的构建信息",
102435
102549
  middleware: ["auth-admin"]
102436
102550
  }).define(async (ctx) => {
102551
+ if (notCNBCheck(ctx))
102552
+ return;
102437
102553
  const labels = [
102438
102554
  {
102439
102555
  title: "CNB_BUILD_ID",
@@ -102572,8 +102688,8 @@ app.route({
102572
102688
  };
102573
102689
  }).addTo(app);
102574
102690
  app.route({
102575
- path: "cnb-board",
102576
- key: "live-pull-info",
102691
+ path: "cnb_board",
102692
+ key: "live_pull_info",
102577
102693
  description: "获取cnb-board live的PR信息",
102578
102694
  middleware: ["auth-admin"]
102579
102695
  }).define(async (ctx) => {
@@ -102670,11 +102786,13 @@ app.route({
102670
102786
  };
102671
102787
  }).addTo(app);
102672
102788
  app.route({
102673
- path: "cnb-board",
102674
- key: "live-npc-info",
102789
+ path: "cnb_board",
102790
+ key: "live_npc_info",
102675
102791
  description: "获取cnb-board live的NPC信息",
102676
102792
  middleware: ["auth-admin"]
102677
102793
  }).define(async (ctx) => {
102794
+ if (notCNBCheck(ctx))
102795
+ return;
102678
102796
  const labels = [
102679
102797
  {
102680
102798
  title: "CNB_NPC_SLUG",
@@ -102713,11 +102831,13 @@ app.route({
102713
102831
  };
102714
102832
  }).addTo(app);
102715
102833
  app.route({
102716
- path: "cnb-board",
102717
- key: "live-comment-info",
102834
+ path: "cnb_board",
102835
+ key: "live_comment_info",
102718
102836
  description: "获取cnb-board live的评论信息",
102719
102837
  middleware: ["auth-admin"]
102720
102838
  }).define(async (ctx) => {
102839
+ if (notCNBCheck(ctx))
102840
+ return;
102721
102841
  const labels = [
102722
102842
  {
102723
102843
  title: "CNB_COMMENT_ID",
@@ -102768,24 +102888,6 @@ app.route({
102768
102888
  isCNB: !!isCNB
102769
102889
  };
102770
102890
  }).addTo(app);
102771
- app.route({
102772
- path: "cnb-board",
102773
- key: "live",
102774
- description: "获取cnb-board live的mdContent内容",
102775
- middleware: ["auth-admin"],
102776
- metadata: {
102777
- args: {
102778
- more: zod_default.boolean().optional().describe("是否获取更多系统信息,默认false")
102779
- }
102780
- }
102781
- }).define(async (ctx) => {
102782
- const more = ctx.query?.more ?? false;
102783
- const list4 = getLiveMdContent({ more });
102784
- ctx.body = {
102785
- title: "开发环境模式配置",
102786
- list: list4
102787
- };
102788
- }).addTo(app);
102789
102891
  app.route({
102790
102892
  path: "cnb-board",
102791
102893
  key: "exit",
@@ -83251,6 +83251,7 @@ class AssistantConfig {
83251
83251
  }
83252
83252
  getDefaultInitAssistantConfig() {
83253
83253
  const id = randomId2();
83254
+ const isCNB = !!useKey2("CNB");
83254
83255
  return {
83255
83256
  app: {
83256
83257
  url: "https://kevisual.cn",
@@ -83258,7 +83259,7 @@ class AssistantConfig {
83258
83259
  },
83259
83260
  description: "助手配置文件",
83260
83261
  docs: "https://kevisual.cn/root/cli/docs/",
83261
- home: "/root/home",
83262
+ home: isCNB ? "/root/cli-center" : "/root/home",
83262
83263
  proxy: [],
83263
83264
  share: {
83264
83265
  enabled: true,
@@ -125163,11 +125164,11 @@ app.route({
125163
125164
  })
125164
125165
  }
125165
125166
  }).define(async (ctx) => {
125166
- const { path: path18, key = "" } = ctx.query;
125167
+ const { path: path18, key = "" } = ctx.args;
125167
125168
  if (!path18) {
125168
125169
  ctx.throw("路径path不能为空");
125169
125170
  }
125170
- const res = await ctx.run({ path: path18, key, payload: ctx.query.payload || {} }, {
125171
+ const res = await ctx.run({ path: path18, key, payload: ctx.args.payload || {} }, {
125171
125172
  ...ctx
125172
125173
  });
125173
125174
  ctx.forward(res);
@@ -127056,20 +127057,22 @@ app.route({
127056
127057
  // src/routes/cnb-board/live/live-content.ts
127057
127058
  var import_dayjs = __toESM(require_dayjs_min(), 1);
127058
127059
  import os7 from "node:os";
127060
+ import { execSync as execSync3 } from "node:child_process";
127059
127061
  var getLiveMdContent = (opts) => {
127060
127062
  const more = opts?.more ?? false;
127061
127063
  const url4 = useKey("CNB_VSCODE_PROXY_URI") || "";
127062
127064
  const token = useKey("CNB_TOKEN") || "";
127063
127065
  const openclawPort = useKey("OPENCLAW_PORT") || "80";
127064
- const openclawUrl = url4?.replace("{{port}}", openclawPort);
127066
+ const openclawUrl = url4.replace("{{port}}", openclawPort);
127065
127067
  const openclawUrlSecret = openclawUrl + "/openclaw?token=" + token;
127066
127068
  const opencodePort = useKey("OPENCODE_PORT") || "100";
127067
- const opencodeUrl = url4?.replace("{{port}}", opencodePort);
127069
+ const opencodeUrl = url4.replace("{{port}}", opencodePort);
127068
127070
  const _opencodeURL = new URL(opencodeUrl);
127069
127071
  _opencodeURL.username = "root";
127070
127072
  _opencodeURL.password = token;
127071
127073
  const opencodeUrlSecret = _opencodeURL.toString();
127072
- const kevisualUrl = url4?.replace("{{port}}", "51515");
127074
+ const kevisualUrl = url4.replace("{{port}}", "51515");
127075
+ const openWebUrl = url4.replace("{{port}}", "200");
127073
127076
  const vscodeWebUrl = useKey("CNB_VSCODE_WEB_URL") || "";
127074
127077
  const TEMPLATE = `# 开发环境模式配置
127075
127078
 
@@ -127077,6 +127080,9 @@ var getLiveMdContent = (opts) => {
127077
127080
  #### nginx 反向代理访问(推荐)
127078
127081
  - OpenClaw: ${openclawUrl + "/openclaw"}
127079
127082
  - OpenCode: ${opencodeUrl}
127083
+ - VSCode Web: ${vscodeWebUrl}
127084
+ - OpenWebUI: ${openWebUrl}
127085
+ - Kevisual: ${kevisualUrl}
127080
127086
 
127081
127087
  ### 直接访问
127082
127088
  - Kevisual: ${kevisualUrl}
@@ -127100,47 +127106,61 @@ var getLiveMdContent = (opts) => {
127100
127106
  - wss: vscode web的websocket地址
127101
127107
  - cookie: vscode web的cookie,保持和浏览器一致
127102
127108
  - url: vscode web的访问地址,可以直接访问vscode web
127103
- 4. 运行cli命令,ev cnb live -c /workspace/live/keep.json
127109
+ 4. 运行cli命令,ev cnb live -c /workspace/live/keep.json.(直接对话opencode或者openclaw调用cnb-live技能即可)
127104
127110
 
127105
127111
  `;
127106
127112
  const labels = [
127107
127113
  {
127108
- title: "vscodeWebUrl",
127114
+ key: "vscodeWebUrl",
127115
+ title: "VSCode Web 地址",
127109
127116
  value: vscodeWebUrl,
127110
127117
  description: "VSCode Web 的访问地址"
127111
127118
  },
127112
127119
  {
127113
- title: "kevisualUrl",
127120
+ key: "kevisualUrl",
127121
+ title: "Kevisual 地址",
127114
127122
  value: kevisualUrl,
127115
127123
  description: "Kevisual 的访问地址,可以通过该地址访问 Kevisual 服务"
127116
127124
  },
127117
127125
  {
127118
- title: "cnbTempToken",
127126
+ key: "cnbTempToken",
127127
+ title: "CNB Token",
127119
127128
  value: token,
127120
127129
  description: "CNB 临时 Token,保持和环境变量 CNB_TOKEN 一致"
127121
127130
  },
127122
127131
  {
127123
- title: "openclawUrl",
127132
+ key: "openWebUrl",
127133
+ title: "OpenWebUI 地址",
127134
+ value: openWebUrl,
127135
+ description: "OpenWebUI 的访问地址,可以通过该地址访问 OpenWebUI 服务"
127136
+ },
127137
+ {
127138
+ key: "openclawUrl",
127139
+ title: "OpenClaw 地址",
127124
127140
  value: openclawUrl,
127125
127141
  description: "OpenClaw 的访问地址,可以通过该地址访问 OpenClaw 服务"
127126
127142
  },
127127
127143
  {
127128
- title: "openclawUrlSecret",
127144
+ key: "openclawUrlSecret",
127145
+ title: "OpenClaw 访问地址(含 Token)",
127129
127146
  value: openclawUrlSecret,
127130
127147
  description: "OpenClaw 的访问地址,包含 token 参数,可以直接访问 OpenClaw 服务"
127131
127148
  },
127132
127149
  {
127133
- title: "opencodeUrl",
127150
+ key: "opencodeUrl",
127151
+ title: "OpenCode 地址",
127134
127152
  value: opencodeUrl,
127135
127153
  description: "OpenCode 的访问地址,可以通过该地址访问 OpenCode 服务"
127136
127154
  },
127137
127155
  {
127138
- title: "opencodeUrlSecret",
127156
+ key: "opencodeUrlSecret",
127157
+ title: "OpenCode 访问地址(含 Token)",
127139
127158
  value: opencodeUrlSecret,
127140
127159
  description: "OpenCode 的访问地址,包含 token 参数,可以直接访问 OpenCode 服务"
127141
127160
  },
127142
127161
  {
127143
- title: "docs",
127162
+ key: "docs",
127163
+ title: "配置说明文档",
127144
127164
  value: TEMPLATE,
127145
127165
  description: "开发环境模式配置说明文档"
127146
127166
  }
@@ -127151,7 +127171,7 @@ var getLiveMdContent = (opts) => {
127151
127171
  };
127152
127172
  var createOSInfo = (more = false) => {
127153
127173
  const labels = [];
127154
- const startTimer = useKey("CNB_BUILD_START_TIME") || 0;
127174
+ const startTimer = useKey("CNB_BUILD_START_TIME") || "";
127155
127175
  const cpus = os7.cpus();
127156
127176
  let totalIdle = 0;
127157
127177
  let totalTick = 0;
@@ -127162,10 +127182,26 @@ var createOSInfo = (more = false) => {
127162
127182
  totalIdle += cpu.times.idle;
127163
127183
  });
127164
127184
  const cpuUsage = ((1 - totalIdle / totalTick) * 100).toFixed(2);
127165
- const totalMem = os7.totalmem();
127166
- const freeMem = os7.freemem();
127167
- const usedMem = totalMem - freeMem;
127168
- const memUsage = (usedMem / totalMem * 100).toFixed(2);
127185
+ let memUsed = 0;
127186
+ let memTotal = 0;
127187
+ let memFree = 0;
127188
+ try {
127189
+ const freeOutput = execSync3("free -b", { encoding: "utf-8" });
127190
+ const lines = freeOutput.trim().split(`
127191
+ `);
127192
+ const memLine = lines.find((line) => line.startsWith("Mem:"));
127193
+ if (memLine) {
127194
+ const parts = memLine.split(/\s+/);
127195
+ memTotal = parseInt(parts[1]);
127196
+ memUsed = parseInt(parts[2]);
127197
+ memFree = parseInt(parts[3]);
127198
+ }
127199
+ } catch (e) {
127200
+ memTotal = os7.totalmem();
127201
+ memFree = os7.freemem();
127202
+ memUsed = memTotal - memFree;
127203
+ }
127204
+ const memUsage = memTotal > 0 ? (memUsed / memTotal * 100).toFixed(2) : "0.00";
127169
127205
  const formatBytes = (bytes) => {
127170
127206
  const sizes = ["B", "KB", "MB", "GB", "TB"];
127171
127207
  if (bytes === 0)
@@ -127173,92 +127209,137 @@ var createOSInfo = (more = false) => {
127173
127209
  const i = Math.floor(Math.log(bytes) / Math.log(1024));
127174
127210
  return (bytes / Math.pow(1024, i)).toFixed(2) + " " + sizes[i];
127175
127211
  };
127176
- const bootTime = os7.uptime();
127177
- const bootTimeDate = new Date(Date.now() - bootTime * 1000);
127178
- const bootTimeStr = import_dayjs.default(bootTimeDate).format("YYYY-MM-DD HH:mm:ss");
127179
127212
  const formatUptime = (seconds) => {
127180
127213
  const days = Math.floor(seconds / 86400);
127181
127214
  const hours = Math.floor(seconds % 86400 / 3600);
127182
127215
  const minutes = Math.floor(seconds % 3600 / 60);
127183
127216
  const secs = Math.floor(seconds % 60);
127184
- return `${days}天 ${hours}小时 ${minutes}分钟 ${secs}秒`;
127185
- };
127186
- const diskInfo = "可通过 df -h 命令获取";
127217
+ let uptimeStr = "";
127218
+ if (days > 0)
127219
+ uptimeStr += `${days}天 `;
127220
+ if (hours > 0)
127221
+ uptimeStr += `${hours}小时 `;
127222
+ if (minutes > 0)
127223
+ uptimeStr += `${minutes}分钟 `;
127224
+ return `${uptimeStr}${secs}秒`;
127225
+ };
127226
+ let diskUsage = "";
127227
+ try {
127228
+ const duOutput = execSync3("du -sh .", { encoding: "utf-8" });
127229
+ diskUsage = duOutput.trim().split("\t")[0];
127230
+ } catch (e) {
127231
+ diskUsage = "获取失败";
127232
+ }
127187
127233
  labels.push({
127188
- title: "cpuUsage",
127234
+ key: "cpuUsage",
127235
+ title: "CPU 使用率",
127189
127236
  value: `${cpuUsage}%`,
127190
127237
  description: "CPU 使用率"
127191
127238
  }, {
127192
- title: "cpuCores",
127239
+ key: "cpuCores",
127240
+ title: "CPU 核心数",
127193
127241
  value: `${cpus.length}`,
127194
127242
  description: "CPU 核心数"
127195
127243
  }, {
127196
- title: "memoryUsed",
127197
- value: formatBytes(usedMem),
127244
+ key: "memoryUsed",
127245
+ title: "已使用内存",
127246
+ value: formatBytes(memUsed),
127198
127247
  description: "已使用内存"
127199
127248
  }, {
127200
- title: "memoryTotal",
127201
- value: formatBytes(totalMem),
127249
+ key: "memoryTotal",
127250
+ title: "总内存",
127251
+ value: formatBytes(memTotal),
127202
127252
  description: "总内存"
127203
127253
  }, {
127204
- title: "memoryUsage",
127254
+ key: "memoryFree",
127255
+ title: "空闲内存",
127256
+ value: formatBytes(memFree),
127257
+ description: "空闲内存"
127258
+ }, {
127259
+ key: "memoryUsage",
127260
+ title: "内存使用率",
127205
127261
  value: `${memUsage}%`,
127206
127262
  description: "内存使用率"
127207
127263
  }, {
127208
- title: "diskInfo",
127209
- value: diskInfo,
127210
- description: "磁盘信息 (请使用 df -h 命令查看)"
127211
- }, {
127212
- title: "bootTime",
127213
- value: bootTimeStr,
127214
- description: "系统启动时间"
127215
- }, {
127216
- title: "uptime",
127217
- value: formatUptime(bootTime),
127218
- description: "系统运行时间"
127264
+ key: "diskUsage",
127265
+ title: "磁盘使用",
127266
+ value: diskUsage,
127267
+ description: "当前目录磁盘使用情况"
127219
127268
  });
127220
127269
  if (startTimer) {
127221
- const buildStartTime = import_dayjs.default(parseInt(startTimer)).format("YYYY-MM-DD HH:mm:ss");
127222
- const buildUptime = Date.now() - parseInt(startTimer);
127270
+ const buildStartTime = import_dayjs.default(startTimer).format("YYYY-MM-DD HH:mm:ss");
127271
+ const buildStartTimestamp = import_dayjs.default(startTimer).valueOf();
127272
+ const buildUptime = Date.now() - buildStartTimestamp;
127223
127273
  const buildUptimeStr = formatUptime(Math.floor(buildUptime / 1000));
127274
+ const maxRunTime = useKey("CNB_PIPELINE_MAX_RUN_TIME") || 0;
127224
127275
  labels.push({
127225
- title: "buildStartTime",
127276
+ key: "buildStartTime",
127277
+ title: "构建启动时间",
127226
127278
  value: buildStartTime,
127227
127279
  description: "构建启动时间"
127228
127280
  }, {
127229
- title: "buildUptime",
127281
+ key: "buildUptime",
127282
+ title: "构建已运行时间",
127230
127283
  value: buildUptimeStr,
127231
127284
  description: "构建已运行时间"
127232
127285
  });
127286
+ if (maxRunTime > 0) {
127287
+ const now = import_dayjs.default();
127288
+ const today4am = now.hour(4).minute(0).second(0).millisecond(0);
127289
+ let timeTo4 = today4am.valueOf() - now.valueOf();
127290
+ if (timeTo4 < 0) {
127291
+ timeTo4 = today4am.add(1, "day").valueOf() - now.valueOf();
127292
+ }
127293
+ const timeTo4Str = `[距离晚上4点重启时间: ${formatUptime(Math.floor(timeTo4 / 1000))}]`;
127294
+ labels.push({
127295
+ key: "buildMaxRunTime",
127296
+ title: "最大运行时间",
127297
+ value: formatUptime(Math.floor(maxRunTime / 1000)),
127298
+ description: "构建最大运行时间(限制时间)"
127299
+ });
127300
+ labels.unshift({
127301
+ key: "remainingTime",
127302
+ title: "剩余时间",
127303
+ value: formatUptime(Math.floor((maxRunTime - buildUptime) / 1000)) + " " + timeTo4Str,
127304
+ description: "构建剩余时间"
127305
+ });
127306
+ }
127233
127307
  }
127234
127308
  if (more) {
127235
127309
  const loadavg = os7.loadavg();
127236
127310
  labels.push({
127237
- title: "hostname",
127311
+ key: "hostname",
127312
+ title: "主机名",
127238
127313
  value: os7.hostname(),
127239
127314
  description: "主机名"
127240
127315
  }, {
127241
- title: "platform",
127316
+ key: "platform",
127317
+ title: "运行平台",
127242
127318
  value: os7.platform(),
127243
127319
  description: "运行平台"
127244
127320
  }, {
127245
- title: "arch",
127321
+ key: "arch",
127322
+ title: "系统架构",
127246
127323
  value: os7.arch(),
127247
127324
  description: "系统架构"
127248
127325
  }, {
127249
- title: "osType",
127326
+ key: "osType",
127327
+ title: "操作系统类型",
127250
127328
  value: os7.type(),
127251
127329
  description: "操作系统类型"
127252
127330
  }, {
127253
- title: "loadavg1m",
127331
+ key: "loadavg1m",
127332
+ title: "系统负载 (1分钟)",
127254
127333
  value: loadavg[0].toFixed(2),
127255
127334
  description: "系统负载 (1分钟)"
127256
127335
  }, {
127257
- title: "loadavg5m",
127336
+ key: "loadavg5m",
127337
+ title: "系统负载 (5分钟)",
127258
127338
  value: loadavg[1].toFixed(2),
127259
127339
  description: "系统负载 (5分钟)"
127260
127340
  }, {
127261
- title: "loadavg15m",
127341
+ key: "loadavg15m",
127342
+ title: "系统负载 (15分钟)",
127262
127343
  value: loadavg[2].toFixed(2),
127263
127344
  description: "系统负载 (15分钟)"
127264
127345
  });
@@ -127267,16 +127348,49 @@ var createOSInfo = (more = false) => {
127267
127348
  };
127268
127349
 
127269
127350
  // src/routes/cnb-board/cnb-dev-env.ts
127351
+ var notCNBCheck = (ctx) => {
127352
+ const isCNB = useKey("CNB");
127353
+ if (!isCNB) {
127354
+ ctx.body = {
127355
+ title: "非 cnb-board 环境",
127356
+ list: []
127357
+ };
127358
+ return true;
127359
+ }
127360
+ return false;
127361
+ };
127270
127362
  app.route({
127271
- path: "cnb-board",
127272
- key: "live-repo-info",
127363
+ path: "cnb_board",
127364
+ key: "live",
127365
+ description: "获取cnb-board live的mdContent内容",
127366
+ middleware: ["auth-admin"],
127367
+ metadata: {
127368
+ args: {
127369
+ more: zod_default.boolean().optional().describe("是否获取更多系统信息,默认false")
127370
+ }
127371
+ }
127372
+ }).define(async (ctx) => {
127373
+ const more = ctx.query?.more ?? false;
127374
+ const list4 = getLiveMdContent({ more });
127375
+ if (notCNBCheck(ctx))
127376
+ return;
127377
+ ctx.body = {
127378
+ title: "开发环境模式配置",
127379
+ list: list4
127380
+ };
127381
+ }).addTo(app);
127382
+ app.route({
127383
+ path: "cnb_board",
127384
+ key: "live_repo_info",
127273
127385
  description: "获取cnb-board live的repo信息",
127274
127386
  middleware: ["auth-admin"]
127275
127387
  }).define(async (ctx) => {
127276
127388
  const repoSlug = useKey("CNB_REPO_SLUG") || "";
127277
127389
  const repoName = useKey("CNB_REPO_NAME") || "";
127278
127390
  const repoId = useKey("CNB_REPO_ID") || "";
127279
- const repoUrlHttps = useKey("CNB_REPO_URL_HTTPS") || "";
127391
+ const repoUrlHttps = useKey("CNB_REPO_UR if (notCNBCheck(ctx)) return;L_HTTPS") || "";
127392
+ if (notCNBCheck(ctx))
127393
+ return;
127280
127394
  const repoNameFromSlug = repoSlug.split("/").pop() || "";
127281
127395
  const labels = [
127282
127396
  {
@@ -127316,11 +127430,13 @@ app.route({
127316
127430
  };
127317
127431
  }).addTo(app);
127318
127432
  app.route({
127319
- path: "cnb-board",
127320
- key: "live-build-info",
127433
+ path: "cnb_board",
127434
+ key: "live_build_info",
127321
127435
  description: "获取cnb-board live的构建信息",
127322
127436
  middleware: ["auth-admin"]
127323
127437
  }).define(async (ctx) => {
127438
+ if (notCNBCheck(ctx))
127439
+ return;
127324
127440
  const labels = [
127325
127441
  {
127326
127442
  title: "CNB_BUILD_ID",
@@ -127459,8 +127575,8 @@ app.route({
127459
127575
  };
127460
127576
  }).addTo(app);
127461
127577
  app.route({
127462
- path: "cnb-board",
127463
- key: "live-pull-info",
127578
+ path: "cnb_board",
127579
+ key: "live_pull_info",
127464
127580
  description: "获取cnb-board live的PR信息",
127465
127581
  middleware: ["auth-admin"]
127466
127582
  }).define(async (ctx) => {
@@ -127557,11 +127673,13 @@ app.route({
127557
127673
  };
127558
127674
  }).addTo(app);
127559
127675
  app.route({
127560
- path: "cnb-board",
127561
- key: "live-npc-info",
127676
+ path: "cnb_board",
127677
+ key: "live_npc_info",
127562
127678
  description: "获取cnb-board live的NPC信息",
127563
127679
  middleware: ["auth-admin"]
127564
127680
  }).define(async (ctx) => {
127681
+ if (notCNBCheck(ctx))
127682
+ return;
127565
127683
  const labels = [
127566
127684
  {
127567
127685
  title: "CNB_NPC_SLUG",
@@ -127600,11 +127718,13 @@ app.route({
127600
127718
  };
127601
127719
  }).addTo(app);
127602
127720
  app.route({
127603
- path: "cnb-board",
127604
- key: "live-comment-info",
127721
+ path: "cnb_board",
127722
+ key: "live_comment_info",
127605
127723
  description: "获取cnb-board live的评论信息",
127606
127724
  middleware: ["auth-admin"]
127607
127725
  }).define(async (ctx) => {
127726
+ if (notCNBCheck(ctx))
127727
+ return;
127608
127728
  const labels = [
127609
127729
  {
127610
127730
  title: "CNB_COMMENT_ID",
@@ -127655,24 +127775,6 @@ app.route({
127655
127775
  isCNB: !!isCNB
127656
127776
  };
127657
127777
  }).addTo(app);
127658
- app.route({
127659
- path: "cnb-board",
127660
- key: "live",
127661
- description: "获取cnb-board live的mdContent内容",
127662
- middleware: ["auth-admin"],
127663
- metadata: {
127664
- args: {
127665
- more: zod_default.boolean().optional().describe("是否获取更多系统信息,默认false")
127666
- }
127667
- }
127668
- }).define(async (ctx) => {
127669
- const more = ctx.query?.more ?? false;
127670
- const list4 = getLiveMdContent({ more });
127671
- ctx.body = {
127672
- title: "开发环境模式配置",
127673
- list: list4
127674
- };
127675
- }).addTo(app);
127676
127778
  app.route({
127677
127779
  path: "cnb-board",
127678
127780
  key: "exit",
@@ -129422,7 +129524,7 @@ import path22 from "node:path";
129422
129524
  // src/module/get-bun-path.ts
129423
129525
  import fs24 from "node:fs";
129424
129526
  import path21 from "node:path";
129425
- import { execSync as execSync3 } from "node:child_process";
129527
+ import { execSync as execSync4 } from "node:child_process";
129426
129528
  var getBunPath = () => {
129427
129529
  const isWindows = process.platform === "win32";
129428
129530
  const bunExecutableName = isWindows ? "bun.exe" : "bun";
@@ -129431,14 +129533,14 @@ var getBunPath = () => {
129431
129533
  }
129432
129534
  if (isWindows) {
129433
129535
  try {
129434
- const globalNodeModules = execSync3("npm root -g", { encoding: "utf-8" }).trim();
129536
+ const globalNodeModules = execSync4("npm root -g", { encoding: "utf-8" }).trim();
129435
129537
  const bunExePath = path21.join(globalNodeModules, "bun", "bin", "bun.exe");
129436
129538
  if (fs24.existsSync(bunExePath)) {
129437
129539
  return bunExePath;
129438
129540
  }
129439
129541
  } catch (error54) {}
129440
129542
  try {
129441
- const bunPath = execSync3("where bun", { encoding: "utf-8" }).trim().split(`
129543
+ const bunPath = execSync4("where bun", { encoding: "utf-8" }).trim().split(`
129442
129544
  `)[0];
129443
129545
  if (bunPath && bunPath.endsWith(".exe")) {
129444
129546
  return bunPath;
@@ -129453,7 +129555,7 @@ var getBunPath = () => {
129453
129555
  } catch (error54) {}
129454
129556
  } else {
129455
129557
  try {
129456
- const bunPath = execSync3("which bun", { encoding: "utf-8" }).trim();
129558
+ const bunPath = execSync4("which bun", { encoding: "utf-8" }).trim();
129457
129559
  if (bunPath && fs24.existsSync(bunPath)) {
129458
129560
  return bunPath;
129459
129561
  }
package/dist/assistant.js CHANGED
@@ -28799,6 +28799,7 @@ class AssistantConfig {
28799
28799
  }
28800
28800
  getDefaultInitAssistantConfig() {
28801
28801
  const id = randomId();
28802
+ const isCNB = !!useKey("CNB");
28802
28803
  return {
28803
28804
  app: {
28804
28805
  url: "https://kevisual.cn",
@@ -28806,7 +28807,7 @@ class AssistantConfig {
28806
28807
  },
28807
28808
  description: "助手配置文件",
28808
28809
  docs: "https://kevisual.cn/root/cli/docs/",
28809
- home: "/root/home",
28810
+ home: isCNB ? "/root/cli-center" : "/root/home",
28810
28811
  proxy: [],
28811
28812
  share: {
28812
28813
  enabled: true,
package/dist/envision.js CHANGED
@@ -22312,8 +22312,8 @@ InitEnv.init();
22312
22312
  var version = useContextKey("version", () => {
22313
22313
  let version2 = "0.0.64";
22314
22314
  try {
22315
- if ("0.1.9")
22316
- version2 = "0.1.9";
22315
+ if ("0.1.12")
22316
+ version2 = "0.1.12";
22317
22317
  } catch (e) {}
22318
22318
  return version2;
22319
22319
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kevisual/cli",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "description": "envision 命令行工具",
5
5
  "type": "module",
6
6
  "basename": "/root/cli",