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.
- package/dist/cli.js +230 -34
- 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: "
|
|
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
|
|
399
|
-
import { mkdir as
|
|
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
|
|
435
|
-
await
|
|
436
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
609
|
+
function describeService3() {
|
|
471
610
|
const r = runSystemctl(["status", systemdUnitName(), "--no-pager"]);
|
|
472
611
|
return r.stdout || r.stderr || "";
|
|
473
612
|
}
|
|
474
|
-
async function
|
|
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
|
|
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: () =>
|
|
677
|
+
stop: () => stop2(),
|
|
519
678
|
stopAndDisableAutostart: () => disableAndStop(),
|
|
520
|
-
restart: () =>
|
|
521
|
-
waitUntilStopped: (timeoutMs) =>
|
|
679
|
+
restart: () => restart2(),
|
|
680
|
+
waitUntilStopped: (timeoutMs) => waitUntilInactive2(timeoutMs),
|
|
522
681
|
deleteFile: async () => {
|
|
523
682
|
await deleteUnit();
|
|
524
683
|
daemonReload();
|
|
525
684
|
},
|
|
526
|
-
describeStatus: () =>
|
|
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")
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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:
|
|
6353
|
+
agent: agentEnabled ? profileConfig.agentKind : agentUnavailable ? "unavailable" : "disabled"
|
|
6162
6354
|
});
|
|
6163
6355
|
console.log(
|
|
6164
|
-
|
|
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.
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
|
|
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(`
|