feishu-devops 0.1.0 → 26.627.1

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.
Files changed (2) hide show
  1. package/dist/cli.js +230 -34
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -4,7 +4,7 @@ import { Command } from "commander";
4
4
  // package.json
5
5
  var package_default = {
6
6
  name: "feishu-devops",
7
- version: "0.1.0",
7
+ version: "26.627.1",
8
8
  description: "\u98DE\u4E66\u6D88\u606F bot\uFF1A\u626B\u7801\u521B\u5EFA\u5E94\u7528\uFF0C\u901A\u8FC7 Claude Code / Codex \u5904\u7406\u6D88\u606F",
9
9
  type: "module",
10
10
  bin: {
@@ -144,6 +144,12 @@ function daemonStdoutPath() {
144
144
  function daemonStderrPath() {
145
145
  return join2(daemonLogDir(), "daemon-stderr.log");
146
146
  }
147
+ function spawnDaemonPidPath() {
148
+ return join2(daemonLogDir(), "bot.pid");
149
+ }
150
+ function spawnDaemonMarkerPath() {
151
+ return join2(daemonLogDir(), ".spawn-daemon");
152
+ }
147
153
 
148
154
  // src/daemon/launchd.ts
149
155
  import { spawnSync } from "child_process";
@@ -393,10 +399,131 @@ async function deleteTask() {
393
399
  return r;
394
400
  }
395
401
 
402
+ // src/daemon/spawn-daemon.ts
403
+ import { spawn } from "child_process";
404
+ import { closeSync, existsSync as existsSync4, openSync, readFileSync, unlinkSync, writeFileSync } from "fs";
405
+ import { mkdir as mkdir3, rm as rm3, writeFile as writeFile3 } from "fs/promises";
406
+ function readPid() {
407
+ if (!existsSync4(spawnDaemonPidPath())) return null;
408
+ const raw = readFileSync(spawnDaemonPidPath(), "utf8").trim();
409
+ const pid = Number.parseInt(raw, 10);
410
+ return Number.isFinite(pid) && pid > 0 ? pid : null;
411
+ }
412
+ function isProcessAlive(pid) {
413
+ try {
414
+ process.kill(pid, 0);
415
+ return true;
416
+ } catch {
417
+ return false;
418
+ }
419
+ }
420
+ function markerExists() {
421
+ return existsSync4(spawnDaemonMarkerPath());
422
+ }
423
+ function isRunning() {
424
+ const pid = readPid();
425
+ if (pid === null) return false;
426
+ if (!isProcessAlive(pid)) {
427
+ try {
428
+ unlinkSync(spawnDaemonPidPath());
429
+ } catch {
430
+ }
431
+ return false;
432
+ }
433
+ return true;
434
+ }
435
+ async function install(extraRunArgs = []) {
436
+ void extraRunArgs;
437
+ await mkdir3(daemonLogDir(), { recursive: true });
438
+ await writeFile3(spawnDaemonMarkerPath(), "spawn-daemon\n", "utf8");
439
+ }
440
+ function start(extraRunArgs = []) {
441
+ if (isRunning()) {
442
+ return { ok: true, stderr: "" };
443
+ }
444
+ const invocation = resolveDaemonRunInvocation(extraRunArgs);
445
+ let outFd;
446
+ let errFd;
447
+ try {
448
+ outFd = openSync(daemonStdoutPath(), "a");
449
+ errFd = openSync(daemonStderrPath(), "a");
450
+ } catch (err) {
451
+ const message = err instanceof Error ? err.message : String(err);
452
+ return { ok: false, stderr: message };
453
+ }
454
+ const child = spawn(invocation.program, invocation.runArgs, {
455
+ detached: true,
456
+ stdio: ["ignore", outFd, errFd],
457
+ cwd: invocation.cwd,
458
+ env: {
459
+ ...process.env,
460
+ PATH: process.env.PATH ?? "",
461
+ FEISHU_DEVOPS_HOME: paths.rootDir
462
+ }
463
+ });
464
+ closeSync(outFd);
465
+ closeSync(errFd);
466
+ if (!child.pid) {
467
+ return { ok: false, stderr: "failed to spawn daemon process" };
468
+ }
469
+ try {
470
+ writeFileSync(spawnDaemonPidPath(), `${child.pid}
471
+ `, "utf8");
472
+ } catch (err) {
473
+ const message = err instanceof Error ? err.message : String(err);
474
+ return { ok: false, stderr: message };
475
+ }
476
+ child.unref();
477
+ return { ok: true, stderr: "" };
478
+ }
479
+ function stop() {
480
+ const pid = readPid();
481
+ if (pid === null || !isProcessAlive(pid)) {
482
+ return { ok: true, stderr: "" };
483
+ }
484
+ try {
485
+ process.kill(pid, "SIGTERM");
486
+ } catch (err) {
487
+ const message = err instanceof Error ? err.message : String(err);
488
+ return { ok: false, stderr: message };
489
+ }
490
+ return { ok: true, stderr: "" };
491
+ }
492
+ function stopAndDisableAutostart() {
493
+ return stop();
494
+ }
495
+ function restart(extraRunArgs = []) {
496
+ const r = stop();
497
+ if (!r.ok) return r;
498
+ return start(extraRunArgs);
499
+ }
500
+ async function waitUntilInactive(timeoutMs = 5e3) {
501
+ const deadline = Date.now() + timeoutMs;
502
+ while (Date.now() < deadline) {
503
+ if (!isRunning()) return true;
504
+ await new Promise((r) => setTimeout(r, 200));
505
+ }
506
+ return false;
507
+ }
508
+ async function deleteMarker() {
509
+ await rm3(spawnDaemonMarkerPath(), { force: true });
510
+ await rm3(spawnDaemonPidPath(), { force: true });
511
+ }
512
+ function describeService2() {
513
+ const pid = readPid();
514
+ if (pid !== null && isProcessAlive(pid)) {
515
+ return `bot (detached): running (pid ${pid})`;
516
+ }
517
+ if (pid !== null) {
518
+ return `bot (detached): not running (stale pid ${pid})`;
519
+ }
520
+ return "bot (detached): not running";
521
+ }
522
+
396
523
  // src/daemon/systemd.ts
397
524
  import { spawnSync as spawnSync3 } from "child_process";
398
- import { existsSync as existsSync4 } from "fs";
399
- import { mkdir as mkdir3, rm as rm3, writeFile as writeFile3 } from "fs/promises";
525
+ import { existsSync as existsSync5 } from "fs";
526
+ import { mkdir as mkdir4, rm as rm4, writeFile as writeFile4 } from "fs/promises";
400
527
  import { dirname as dirname4 } from "path";
401
528
  function buildUnit(inputs) {
402
529
  const escape = (s) => s.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
@@ -431,12 +558,12 @@ async function writeUnit(extraRunArgs = []) {
431
558
  cwd: invocation.cwd
432
559
  });
433
560
  const unitPath = systemdUnitPath();
434
- await mkdir3(dirname4(unitPath), { recursive: true });
435
- await mkdir3(daemonLogDir(), { recursive: true });
436
- await writeFile3(unitPath, content, "utf8");
561
+ await mkdir4(dirname4(unitPath), { recursive: true });
562
+ await mkdir4(daemonLogDir(), { recursive: true });
563
+ await writeFile4(unitPath, content, "utf8");
437
564
  }
438
565
  function unitExists() {
439
- return existsSync4(systemdUnitPath());
566
+ return existsSync5(systemdUnitPath());
440
567
  }
441
568
  function runSystemctl(args) {
442
569
  const r = spawnSync3("systemctl", ["--user", ...args], { encoding: "utf8" });
@@ -446,19 +573,31 @@ function runSystemctl(args) {
446
573
  stdout: r.stdout ?? ""
447
574
  };
448
575
  }
576
+ function isUserBusAvailable() {
577
+ const r = spawnSync3("systemctl", ["--user", "is-system-running"], {
578
+ encoding: "utf8",
579
+ stdio: ["ignore", "pipe", "pipe"]
580
+ });
581
+ const combined = `${r.stderr ?? ""}
582
+ ${r.stdout ?? ""}`;
583
+ if (/Failed to connect to bus|Couldn't connect to bus|No medium found|找不到介质/i.test(combined)) {
584
+ return false;
585
+ }
586
+ return r.status !== null;
587
+ }
449
588
  function daemonReload() {
450
589
  return runSystemctl(["daemon-reload"]);
451
590
  }
452
591
  function enableAndStart() {
453
592
  return runSystemctl(["enable", "--now", systemdUnitName()]);
454
593
  }
455
- function stop() {
594
+ function stop2() {
456
595
  return runSystemctl(["stop", systemdUnitName()]);
457
596
  }
458
597
  function disableAndStop() {
459
598
  return runSystemctl(["disable", "--now", systemdUnitName()]);
460
599
  }
461
- function restart() {
600
+ function restart2() {
462
601
  return runSystemctl(["restart", systemdUnitName()]);
463
602
  }
464
603
  function isActive() {
@@ -467,11 +606,11 @@ function isActive() {
467
606
  });
468
607
  return r.status === 0;
469
608
  }
470
- function describeService2() {
609
+ function describeService3() {
471
610
  const r = runSystemctl(["status", systemdUnitName(), "--no-pager"]);
472
611
  return r.stdout || r.stderr || "";
473
612
  }
474
- async function waitUntilInactive(timeoutMs = 5e3) {
613
+ async function waitUntilInactive2(timeoutMs = 5e3) {
475
614
  const deadline = Date.now() + timeoutMs;
476
615
  while (Date.now() < deadline) {
477
616
  if (!isActive()) return true;
@@ -480,7 +619,7 @@ async function waitUntilInactive(timeoutMs = 5e3) {
480
619
  return false;
481
620
  }
482
621
  async function deleteUnit() {
483
- await rm3(systemdUnitPath(), { force: true });
622
+ await rm4(systemdUnitPath(), { force: true });
484
623
  }
485
624
 
486
625
  // src/daemon/service-adapter.ts
@@ -504,6 +643,26 @@ function makeLaunchdAdapter(extraRunArgs) {
504
643
  })
505
644
  };
506
645
  }
646
+ function makeSpawnDaemonAdapter(extraRunArgs) {
647
+ return {
648
+ platformName: "detached process (Linux fallback)",
649
+ fileExists: () => markerExists(),
650
+ isRunning: () => isRunning(),
651
+ servicePath: () => spawnDaemonPidPath(),
652
+ install: () => install(extraRunArgs),
653
+ start: () => start(extraRunArgs),
654
+ stop: () => stop(),
655
+ stopAndDisableAutostart: () => stopAndDisableAutostart(),
656
+ restart: () => restart(extraRunArgs),
657
+ waitUntilStopped: (timeoutMs) => waitUntilInactive(timeoutMs),
658
+ deleteFile: () => deleteMarker(),
659
+ describeStatus: () => describeService2(),
660
+ parseStatus: (text) => ({
661
+ pid: text.match(/pid[:\s]+(\d+)/i)?.[1],
662
+ lastExit: void 0
663
+ })
664
+ };
665
+ }
507
666
  function makeSystemdAdapter(extraRunArgs) {
508
667
  return {
509
668
  platformName: "systemd (Linux user)",
@@ -515,15 +674,15 @@ function makeSystemdAdapter(extraRunArgs) {
515
674
  daemonReload();
516
675
  },
517
676
  start: () => enableAndStart(),
518
- stop: () => stop(),
677
+ stop: () => stop2(),
519
678
  stopAndDisableAutostart: () => disableAndStop(),
520
- restart: () => restart(),
521
- waitUntilStopped: (timeoutMs) => waitUntilInactive(timeoutMs),
679
+ restart: () => restart2(),
680
+ waitUntilStopped: (timeoutMs) => waitUntilInactive2(timeoutMs),
522
681
  deleteFile: async () => {
523
682
  await deleteUnit();
524
683
  daemonReload();
525
684
  },
526
- describeStatus: () => describeService2(),
685
+ describeStatus: () => describeService3(),
527
686
  parseStatus: (text) => ({
528
687
  pid: text.match(/Main PID:\s*(\d+)/)?.[1],
529
688
  lastExit: text.match(/Process:\s+\d+\s+ExecStart=.*status=(\d+)/)?.[1]
@@ -557,7 +716,9 @@ function makeSchtasksAdapter(extraRunArgs) {
557
716
  }
558
717
  function getServiceAdapter(extraRunArgs = []) {
559
718
  if (process.platform === "darwin") return makeLaunchdAdapter(extraRunArgs);
560
- if (process.platform === "linux") return makeSystemdAdapter(extraRunArgs);
719
+ if (process.platform === "linux") {
720
+ return isUserBusAvailable() ? makeSystemdAdapter(extraRunArgs) : makeSpawnDaemonAdapter(extraRunArgs);
721
+ }
561
722
  if (process.platform === "win32") return makeSchtasksAdapter(extraRunArgs);
562
723
  return null;
563
724
  }
@@ -619,7 +780,7 @@ import { readFile } from "fs/promises";
619
780
 
620
781
  // src/platform/atomic-write.ts
621
782
  import { randomBytes } from "crypto";
622
- import { chmod, mkdir as mkdir4, open, rm as rm4 } from "fs/promises";
783
+ import { chmod, mkdir as mkdir5, open, rm as rm5 } from "fs/promises";
623
784
  import { basename, dirname as dirname5, join as join4 } from "path";
624
785
  import { promisify } from "util";
625
786
  import gracefulFs from "graceful-fs";
@@ -627,7 +788,7 @@ var gracefulRename = promisify(gracefulFs.rename);
627
788
  var DEFAULT_RENAME_ATTEMPTS = 5;
628
789
  var DEFAULT_RETRY_DELAY_MS = 25;
629
790
  async function writeFileAtomic(path, data, opts = {}) {
630
- await mkdir4(dirname5(path), { recursive: true });
791
+ await mkdir5(dirname5(path), { recursive: true });
631
792
  const tmp = join4(
632
793
  dirname5(path),
633
794
  `.${basename(path)}.tmp-${process.pid}-${Date.now()}-${randomBytes(3).toString("hex")}`
@@ -647,7 +808,7 @@ async function writeFileAtomic(path, data, opts = {}) {
647
808
  await chmod(tmp, opts.mode ?? 384);
648
809
  await renameWithRetry(tmp, path, opts);
649
810
  } catch (err) {
650
- await rm4(tmp, { force: true }).catch(() => {
811
+ await rm5(tmp, { force: true }).catch(() => {
651
812
  });
652
813
  throw err;
653
814
  }
@@ -835,6 +996,22 @@ function printServiceFailure(stderr) {
835
996
  console.error(` ${cleaned}`);
836
997
  return;
837
998
  }
999
+ if (/Failed to connect to bus|Couldn't connect to bus|No medium found|找不到介质/i.test(cleaned)) {
1000
+ console.error("\u2717 bot \u542F\u52A8\u5931\u8D25\u3002");
1001
+ console.error("");
1002
+ console.error("\u5F53\u524D\u73AF\u5883\u65E0\u6CD5\u8FDE\u63A5 systemd \u7528\u6237 D-Bus\uFF08\u5E38\u89C1\u4E8E SSH\u3001Docker\u3001\u65E0\u56FE\u5F62\u4F1A\u8BDD\uFF09\u3002");
1003
+ console.error("");
1004
+ console.error("\u53EF\u9009\u65B9\u6848\uFF1A");
1005
+ console.error(" 1. \u524D\u53F0\u8FD0\u884C: feishu-devops run");
1006
+ console.error(" 2. \u542F\u7528 systemd \u7528\u6237\u4F1A\u8BDD\u540E\u91CD\u8BD5:");
1007
+ console.error(" export XDG_RUNTIME_DIR=/run/user/$(id -u)");
1008
+ console.error(" sudo loginctl enable-linger $USER");
1009
+ console.error(" npm start");
1010
+ console.error("");
1011
+ console.error("\u539F\u59CB\u9519\u8BEF:");
1012
+ console.error(` ${cleaned}`);
1013
+ return;
1014
+ }
838
1015
  console.error("\u2717 bot \u542F\u52A8\u5931\u8D25:");
839
1016
  console.error(cleaned);
840
1017
  }
@@ -880,6 +1057,9 @@ ${formatServiceStderr(r2.stderr)}`);
880
1057
  process.exit(1);
881
1058
  }
882
1059
  console.log("\u2713 bot \u5DF2\u5728\u540E\u53F0\u542F\u52A8");
1060
+ if (adapter.platformName.includes("fallback")) {
1061
+ console.log(" \u540E\u53F0\u65B9\u5F0F: detached \u8FDB\u7A0B\uFF08systemd \u7528\u6237\u4F1A\u8BDD\u4E0D\u53EF\u7528\uFF09");
1062
+ }
883
1063
  console.log(" \u65E5\u5FD7:");
884
1064
  console.log(` ${daemonStdoutPath()}`);
885
1065
  console.log(` ${daemonStderrPath()}`);
@@ -934,6 +1114,9 @@ async function runServiceRestart(opts = {}) {
934
1114
  process.exit(1);
935
1115
  }
936
1116
  console.log("\u2713 bot \u5DF2\u5728\u540E\u53F0\u542F\u52A8");
1117
+ if (adapter.platformName.includes("fallback")) {
1118
+ console.log(" \u540E\u53F0\u65B9\u5F0F: detached \u8FDB\u7A0B\uFF08systemd \u7528\u6237\u4F1A\u8BDD\u4E0D\u53EF\u7528\uFF09");
1119
+ }
937
1120
  console.log(" \u65E5\u5FD7:");
938
1121
  console.log(` ${daemonStdoutPath()}`);
939
1122
  console.log(` ${daemonStderrPath()}`);
@@ -970,7 +1153,7 @@ import { createInterface as createInterface2 } from "readline";
970
1153
  // src/core/logger.ts
971
1154
  import { AsyncLocalStorage } from "async_hooks";
972
1155
  import { createWriteStream, mkdirSync } from "fs";
973
- import { open as open2, readdir, rm as rm5, stat } from "fs/promises";
1156
+ import { open as open2, readdir, rm as rm6, stat } from "fs/promises";
974
1157
  import { join as join5 } from "path";
975
1158
 
976
1159
  // src/core/telemetry.ts
@@ -3674,7 +3857,7 @@ function isTerminalEvent(event) {
3674
3857
 
3675
3858
  // src/session/catalog.ts
3676
3859
  import { randomUUID as randomUUID2 } from "crypto";
3677
- import { open as open3, readFile as readFile2, rename, mkdir as mkdir5 } from "fs/promises";
3860
+ import { open as open3, readFile as readFile2, rename, mkdir as mkdir6 } from "fs/promises";
3678
3861
  import { dirname as dirname6 } from "path";
3679
3862
  var DEFAULT_MAX_ARCHIVED_AGE_MS = 90 * 24 * 60 * 60 * 1e3;
3680
3863
  var DEFAULT_MAX_ENTRIES_PER_SCOPE = 20;
@@ -3797,7 +3980,7 @@ var SessionCatalog = class {
3797
3980
  });
3798
3981
  }
3799
3982
  async persist() {
3800
- await mkdir5(dirname6(this.path), { recursive: true });
3983
+ await mkdir6(dirname6(this.path), { recursive: true });
3801
3984
  const tmp = `${this.path}.${process.pid}.${Date.now()}.${randomUUID2()}.tmp`;
3802
3985
  const payload = `${JSON.stringify(this.entries(), null, 2)}
3803
3986
  `;
@@ -5419,14 +5602,14 @@ function normalizeCommandInput(msg) {
5419
5602
  }
5420
5603
 
5421
5604
  // src/bot/run-shell.ts
5422
- import { spawn } from "child_process";
5605
+ import { spawn as spawn2 } from "child_process";
5423
5606
  var DEFAULT_TIMEOUT_MS = 3e5;
5424
5607
  var MAX_OUTPUT_CHARS = 3500;
5425
5608
  async function runShellCommand(command, opts = {}) {
5426
5609
  const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
5427
5610
  const cwd = opts.cwd ?? process.cwd();
5428
5611
  return new Promise((resolve3) => {
5429
- const child = spawn(command, {
5612
+ const child = spawn2(command, {
5430
5613
  shell: true,
5431
5614
  cwd,
5432
5615
  env: process.env,
@@ -5780,7 +5963,7 @@ async function handleStatus(_args, ctx) {
5780
5963
  effectiveCwd: effective,
5781
5964
  sessionId: isCodex ? catalogEntry?.threadId : sess?.sessionId,
5782
5965
  sessionStale: usesSessionStore && Boolean(cwd && sess && sess.cwd !== cwd),
5783
- agentName: ctx.agent?.displayName ?? profile?.agentKind ?? "unknown",
5966
+ agentName: resolveStatusAgentName(ctx),
5784
5967
  runtimeAccess: runtimeAccessStatus(profile),
5785
5968
  activeRun: Boolean(ctx.activeRuns?.get(ctx.scope)),
5786
5969
  queue: ctx.processPool?.snapshot(),
@@ -5886,6 +6069,13 @@ async function handleSwitch(args, ctx) {
5886
6069
  function isSwitchableAgentKind(value) {
5887
6070
  return value === "claude" || value === "codex" || value === "cursor";
5888
6071
  }
6072
+ function resolveStatusAgentName(ctx) {
6073
+ if (ctx.runtime?.agentUnavailable) {
6074
+ const kind = ctx.profileConfig?.agentKind ?? "agent";
6075
+ return `${kind}\uFF08\u4E0D\u53EF\u7528\uFF09`;
6076
+ }
6077
+ return ctx.agent?.displayName ?? ctx.profileConfig?.agentKind ?? "unknown";
6078
+ }
5889
6079
  function runtimeAccessStatus(profile) {
5890
6080
  if (!profile) return { label: "access", value: "unknown" };
5891
6081
  if (profile.agentKind === "claude") {
@@ -6023,8 +6213,9 @@ function log2(level, phase, detail) {
6023
6213
  async function startChannel(cfg, startOpts = {}) {
6024
6214
  const fullCfg = startOpts.cfg ?? cfg;
6025
6215
  const configPath = startOpts.configPath ?? paths.configFile;
6216
+ const profileConfig = toProfileConfig(fullCfg);
6026
6217
  const agentEnabled = Boolean(startOpts.agent) && isAgentEnabled(fullCfg);
6027
- const profileConfig = agentEnabled ? toProfileConfig(fullCfg) : void 0;
6218
+ const agentUnavailable = startOpts.agentUnavailable === true;
6028
6219
  configureLogger({ logsDir: `${paths.rootDir}/logs` });
6029
6220
  const { app } = cfg.accounts;
6030
6221
  const workspaces = startOpts.workspaces ?? new WorkspaceStore();
@@ -6048,6 +6239,7 @@ async function startChannel(cfg, startOpts = {}) {
6048
6239
  agent: startOpts.agent,
6049
6240
  executor: agentEnabled && startOpts.agent ? new RunExecutor({ agent: startOpts.agent, pool, activeRuns }) : void 0,
6050
6241
  agentEnabled,
6242
+ agentUnavailable,
6051
6243
  cursorDebug: startOpts.cursorDebug === true,
6052
6244
  configPath
6053
6245
  };
@@ -6158,10 +6350,11 @@ async function startChannel(cfg, startOpts = {}) {
6158
6350
  bot: identity?.name ?? "unknown",
6159
6351
  openId: identity?.openId ?? "-",
6160
6352
  appId: app.id,
6161
- agent: runtime.agentEnabled ? runtime.profileConfig?.agentKind : "disabled"
6353
+ agent: agentEnabled ? profileConfig.agentKind : agentUnavailable ? "unavailable" : "disabled"
6162
6354
  });
6163
6355
  console.log(
6164
- runtime.agentEnabled ? `\u6B63\u5728\u76D1\u542C\u6D88\u606F\uFF08agent: ${runtime.profileConfig?.agentKind ?? "unknown"}\uFF09\u3002\u6309 Ctrl+C \u9000\u51FA\u3002
6356
+ agentEnabled ? `\u6B63\u5728\u76D1\u542C\u6D88\u606F\uFF08agent: ${profileConfig.agentKind}\uFF09\u3002\u6309 Ctrl+C \u9000\u51FA\u3002
6357
+ ` : agentUnavailable ? `\u6B63\u5728\u76D1\u542C\u6D88\u606F\uFF08agent \u4E0D\u53EF\u7528\uFF0C\u659C\u6760\u547D\u4EE4\u4E0E\u56FA\u5B9A\u56DE\u590D\u4ECD\u53EF\u7528\uFF09\u3002\u6309 Ctrl+C \u9000\u51FA\u3002
6165
6358
  ` : "\u6B63\u5728\u76D1\u542C\u6D88\u606F\u3002\u6309 Ctrl+C \u9000\u51FA\u3002\n"
6166
6359
  );
6167
6360
  return {
@@ -6278,14 +6471,16 @@ async function runStart(opts) {
6278
6471
  const sessionCatalog = new SessionCatalog();
6279
6472
  await sessionCatalog.load();
6280
6473
  let agent;
6474
+ let agentUnavailable = false;
6281
6475
  if (agentKind !== "disabled") {
6282
6476
  agent = createRuntimeAgent(fullCfg, { configPath, cursorDebug: opts.debug });
6283
6477
  const availability = await checkRuntimeAgentAvailability(agent);
6284
6478
  if (!availability.ok) {
6285
- console.error(availability.message);
6286
- process.exit(1);
6287
- }
6288
- if (agentKind === "claude") {
6479
+ console.warn("\u26A0 Agent \u4E0D\u53EF\u7528\uFF0C\u670D\u52A1\u5C06\u4EE5\u65E0 Agent \u6A21\u5F0F\u542F\u52A8\uFF08/cmd\u3001/status \u7B49\u547D\u4EE4\u4ECD\u53EF\u7528\uFF09");
6480
+ console.warn(availability.message);
6481
+ agent = void 0;
6482
+ agentUnavailable = true;
6483
+ } else if (agentKind === "claude") {
6289
6484
  try {
6290
6485
  const claudePath = await resolveClaudeBinaryPath();
6291
6486
  console.log(`\u2713 Claude Code: ${claudePath}`);
@@ -6309,7 +6504,8 @@ async function runStart(opts) {
6309
6504
  sessions,
6310
6505
  sessionCatalog,
6311
6506
  cursorDebug: opts.debug,
6312
- configPath
6507
+ configPath,
6508
+ agentUnavailable
6313
6509
  });
6314
6510
  const shutdown = async (signal) => {
6315
6511
  console.log(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "feishu-devops",
3
- "version": "0.1.0",
3
+ "version": "26.627.1",
4
4
  "description": "飞书消息 bot:扫码创建应用,通过 Claude Code / Codex 处理消息",
5
5
  "type": "module",
6
6
  "bin": {