dsh-lark-bot 0.19.2 → 0.19.3
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/README.md +3 -1
- package/dist/cli.js +240 -52
- package/dist/cli.js.map +1 -1
- package/dist/plugin.d.ts +2 -0
- package/dist/plugin.js +66 -28
- package/dist/plugin.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -334,7 +334,7 @@ profile 的前台进程会拒绝并提示先停止,生命周期锁阻止并发
|
|
|
334
334
|
|
|
335
335
|
### 升级
|
|
336
336
|
|
|
337
|
-
**完全不接触命令行:** profile 管理员在飞书发送 `/upgrade`。有新版本时 bot 弹出只允许发起人操作的确认卡;点击“确认更新”后,Guardian 通过独立 worker 安装卡片中确认的精确 npm 版本,复用完整升级、runtime profile 修复、guardian/profile 重启和 doctor
|
|
337
|
+
**完全不接触命令行:** profile 管理员在飞书发送 `/upgrade`。有新版本时 bot 弹出只允许发起人操作的确认卡;点击“确认更新”后,Guardian 通过独立 worker 安装卡片中确认的精确 npm 版本,复用完整升级、runtime profile 修复、guardian/profile 重启和 doctor 验证链,并在重载后回到原会话报告结果。worker 使用 owner-only 中立工作目录与每次请求隔离的 npm cache,不依赖 bridge 启动目录或用户全局 npm cache;失败时只回传脱敏的可行动类别,不发送原始命令输出。点击“取消”不会产生任何变更。更新会重启机器人,正在执行的任务可能被中断;配置、会话、归档和凭据保持不变。每次 `/new` / `/reset` 都会 best-effort 查询一次 npm;仅在有新版本时额外发送一条简短普通消息。
|
|
338
338
|
|
|
339
339
|
**推荐:一行命令彻底升级(v0.12.0+ 新增,issue #10)**
|
|
340
340
|
|
|
@@ -724,6 +724,8 @@ pnpm publish:dual
|
|
|
724
724
|
默认安装的「安全网守护」(`src/guardian/`)独立于 dsh 进程常驻:dsh 在线时静默,下线时接管飞书
|
|
725
725
|
通道接收 `/safemode` 控制信号,以仅核心 profile(`dsh-base` + `dsh-headless`)拉起受限对话
|
|
726
726
|
用于自愈,`/safemode exit` 重启完整 profile 并交还通道。
|
|
727
|
+
`dsh-lark-bot guardian status` 只报告精确 `guardian run` 进程身份唯一且存活的常驻 PID,并在
|
|
728
|
+
系统服务 PID 可用时交叉验证;身份不确定时显示“未发现”,不会把查询命令自身 PID 当成守护进程。
|
|
727
729
|
|
|
728
730
|
## 目录结构
|
|
729
731
|
|
package/dist/cli.js
CHANGED
|
@@ -838,14 +838,67 @@ var init_acp_adapter = __esm({
|
|
|
838
838
|
var process_exports = {};
|
|
839
839
|
__export(process_exports, {
|
|
840
840
|
captureOutput: () => captureOutput,
|
|
841
|
+
findGuardianProcess: () => findGuardianProcess,
|
|
841
842
|
findProfileProcess: () => findProfileProcess,
|
|
842
843
|
isProcessAlive: () => isProcessAlive,
|
|
843
844
|
listProcesses: () => listProcesses,
|
|
844
845
|
looksLikeDshProcess: () => looksLikeDshProcess,
|
|
846
|
+
matchGuardianProcess: () => matchGuardianProcess,
|
|
845
847
|
matchProfileProcess: () => matchProfileProcess,
|
|
846
848
|
spawnDetached: () => spawnDetached
|
|
847
849
|
});
|
|
848
850
|
import { spawn as spawn5 } from "child_process";
|
|
851
|
+
function commandTokens(cmdline) {
|
|
852
|
+
const tokens = [];
|
|
853
|
+
let token = "";
|
|
854
|
+
let quote;
|
|
855
|
+
const input = cmdline.trim();
|
|
856
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
857
|
+
const character = input[index] ?? "";
|
|
858
|
+
const next = input[index + 1];
|
|
859
|
+
if (character === "\\" && quote === void 0 && next !== void 0 && /[\s\\"']/u.test(next)) {
|
|
860
|
+
token += next;
|
|
861
|
+
index += 1;
|
|
862
|
+
} else if (character === "\\" && quote === '"' && next === '"') {
|
|
863
|
+
token += next;
|
|
864
|
+
index += 1;
|
|
865
|
+
} else if (quote !== void 0) {
|
|
866
|
+
if (character === quote) quote = void 0;
|
|
867
|
+
else token += character;
|
|
868
|
+
} else if (character === '"' || character === "'") {
|
|
869
|
+
quote = character;
|
|
870
|
+
} else if (/\s/u.test(character)) {
|
|
871
|
+
if (token !== "") {
|
|
872
|
+
tokens.push(token);
|
|
873
|
+
token = "";
|
|
874
|
+
}
|
|
875
|
+
} else {
|
|
876
|
+
token += character;
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
if (token !== "") tokens.push(token);
|
|
880
|
+
return tokens;
|
|
881
|
+
}
|
|
882
|
+
function isGuardianCliEntry(token) {
|
|
883
|
+
const normalized = token.replace(/\\/gu, "/").toLowerCase();
|
|
884
|
+
return normalized.endsWith("/dist/cli.js") && (normalized.includes("/dsh-lark-bot/") || normalized.includes("/dsh-feishu-bot/"));
|
|
885
|
+
}
|
|
886
|
+
function hasOnlyGuardianRunOptions(tokens) {
|
|
887
|
+
for (let index = 0; index < tokens.length; index += 2) {
|
|
888
|
+
if (tokens[index] !== "--dsh-profile" && tokens[index] !== "--bridge-profile") return false;
|
|
889
|
+
if (tokens[index + 1] === void 0 || tokens[index + 1]?.startsWith("--")) return false;
|
|
890
|
+
}
|
|
891
|
+
return true;
|
|
892
|
+
}
|
|
893
|
+
function matchGuardianProcess(cmdline) {
|
|
894
|
+
const tokens = commandTokens(cmdline);
|
|
895
|
+
const cliIndex = tokens.findIndex(isGuardianCliEntry);
|
|
896
|
+
if (cliIndex < 1) return false;
|
|
897
|
+
const executable = tokens[cliIndex - 1]?.replace(/\\/gu, "/").split("/").pop()?.toLowerCase();
|
|
898
|
+
if (executable !== "node" && executable !== "node.exe") return false;
|
|
899
|
+
if (tokens[cliIndex + 1] !== "guardian" || tokens[cliIndex + 2] !== "run") return false;
|
|
900
|
+
return hasOnlyGuardianRunOptions(tokens.slice(cliIndex + 3));
|
|
901
|
+
}
|
|
849
902
|
function hasProfileFlag(cmdline, dshProfile) {
|
|
850
903
|
const pattern = new RegExp(
|
|
851
904
|
`(?:^|\\s)--profile(?:\\s+|=)${escapeRegExp(dshProfile)}(?:\\s|$)`
|
|
@@ -865,14 +918,14 @@ function matchProfileProcess(cmdline, dshProfile) {
|
|
|
865
918
|
if (/(?:^|\s)plugin(?:\s|$)/.test(cmdline)) return false;
|
|
866
919
|
return hasProfileFlag(cmdline, dshProfile) && looksLikeDshProcess(cmdline);
|
|
867
920
|
}
|
|
868
|
-
async function listProcesses() {
|
|
869
|
-
if (
|
|
870
|
-
return listProcessesWindows();
|
|
921
|
+
async function listProcesses(platform = process.platform, run = captureOutput) {
|
|
922
|
+
if (platform === "win32") {
|
|
923
|
+
return listProcessesWindows(run);
|
|
871
924
|
}
|
|
872
|
-
return listProcessesPosix();
|
|
925
|
+
return listProcessesPosix(run);
|
|
873
926
|
}
|
|
874
|
-
async function listProcessesPosix() {
|
|
875
|
-
const { stdout } = await
|
|
927
|
+
async function listProcessesPosix(run) {
|
|
928
|
+
const { stdout } = await run("ps", ["-axo", "pid=,args="], 1e4);
|
|
876
929
|
const result = [];
|
|
877
930
|
for (const line of stdout.split("\n")) {
|
|
878
931
|
const match = /^\s*(\d+)\s+(.+)$/.exec(line);
|
|
@@ -882,33 +935,46 @@ async function listProcessesPosix() {
|
|
|
882
935
|
}
|
|
883
936
|
return result;
|
|
884
937
|
}
|
|
885
|
-
async function listProcessesWindows() {
|
|
886
|
-
const { stdout } = await
|
|
938
|
+
async function listProcessesWindows(run) {
|
|
939
|
+
const { stdout } = await run(
|
|
887
940
|
"powershell.exe",
|
|
888
941
|
[
|
|
889
942
|
"-NoProfile",
|
|
890
943
|
"-NonInteractive",
|
|
891
944
|
"-Command",
|
|
892
|
-
"Get-CimInstance Win32_Process | Select-Object ProcessId, CommandLine | ConvertTo-
|
|
945
|
+
"Get-CimInstance Win32_Process | Select-Object ProcessId, CommandLine | ConvertTo-Json -Compress"
|
|
893
946
|
],
|
|
894
947
|
1e4
|
|
895
948
|
);
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
const
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
949
|
+
try {
|
|
950
|
+
const parsed = JSON.parse(stdout);
|
|
951
|
+
const rows = Array.isArray(parsed) ? parsed : [parsed];
|
|
952
|
+
return rows.flatMap((row) => {
|
|
953
|
+
if (typeof row !== "object" || row === null) return [];
|
|
954
|
+
const record = row;
|
|
955
|
+
const pid = Number(record.ProcessId);
|
|
956
|
+
const cmdline = record.CommandLine;
|
|
957
|
+
return Number.isInteger(pid) && pid > 0 && typeof cmdline === "string" ? [{ pid, cmdline }] : [];
|
|
958
|
+
});
|
|
959
|
+
} catch {
|
|
960
|
+
return [];
|
|
903
961
|
}
|
|
904
|
-
return result;
|
|
905
962
|
}
|
|
906
|
-
async function captureOutput(command, args, timeoutMs = 3e4) {
|
|
963
|
+
async function captureOutput(command, args, timeoutMs = 3e4, options = {}) {
|
|
907
964
|
return new Promise((resolve6) => {
|
|
908
|
-
const
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
965
|
+
const previousUmask = options.umask !== void 0 && process.platform !== "win32" ? process.umask(options.umask) : void 0;
|
|
966
|
+
const child = (() => {
|
|
967
|
+
try {
|
|
968
|
+
return spawn5(command, [...args], {
|
|
969
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
970
|
+
windowsHide: true,
|
|
971
|
+
...options.cwd ? { cwd: options.cwd } : {},
|
|
972
|
+
...options.env ? { env: options.env } : {}
|
|
973
|
+
});
|
|
974
|
+
} finally {
|
|
975
|
+
if (previousUmask !== void 0) process.umask(previousUmask);
|
|
976
|
+
}
|
|
977
|
+
})();
|
|
912
978
|
let stdout = "";
|
|
913
979
|
let stderr = "";
|
|
914
980
|
child.stdout?.on("data", (chunk) => {
|
|
@@ -934,6 +1000,47 @@ async function findProfileProcess(dshProfile) {
|
|
|
934
1000
|
const processes = await listProcesses();
|
|
935
1001
|
return processes.find((entry) => matchProfileProcess(entry.cmdline, dshProfile));
|
|
936
1002
|
}
|
|
1003
|
+
async function managedGuardianPid(platform, run, uid) {
|
|
1004
|
+
let result;
|
|
1005
|
+
if (platform === "linux") {
|
|
1006
|
+
result = await run(
|
|
1007
|
+
"systemctl",
|
|
1008
|
+
["--user", "show", "dsh-lark-guardian.service", "--property=MainPID", "--value"],
|
|
1009
|
+
1e4
|
|
1010
|
+
);
|
|
1011
|
+
} else if (platform === "darwin") {
|
|
1012
|
+
result = await run(
|
|
1013
|
+
"launchctl",
|
|
1014
|
+
["print", `gui/${uid}/io.dsh-lark.dsh-lark-guardian`],
|
|
1015
|
+
1e4
|
|
1016
|
+
);
|
|
1017
|
+
} else {
|
|
1018
|
+
return void 0;
|
|
1019
|
+
}
|
|
1020
|
+
if (result.code !== 0) return void 0;
|
|
1021
|
+
const raw = platform === "darwin" ? /(?:^|\n)\s*pid\s*=\s*(\d+)\s*(?:\n|$)/u.exec(result.stdout)?.[1] : /^(\d+)\s*$/u.exec(result.stdout.trim())?.[1];
|
|
1022
|
+
const pid = Number(raw);
|
|
1023
|
+
return Number.isInteger(pid) && pid > 0 ? pid : void 0;
|
|
1024
|
+
}
|
|
1025
|
+
async function findGuardianProcess(options = {}) {
|
|
1026
|
+
const platform = options.platform ?? process.platform;
|
|
1027
|
+
const run = options.run ?? captureOutput;
|
|
1028
|
+
const isAlive = options.isAlive ?? isProcessAlive;
|
|
1029
|
+
const currentPid = options.currentPid ?? process.pid;
|
|
1030
|
+
const candidates = (await listProcesses(platform, run)).filter(
|
|
1031
|
+
(entry) => entry.pid !== currentPid && matchGuardianProcess(entry.cmdline) && isAlive(entry.pid)
|
|
1032
|
+
);
|
|
1033
|
+
if (candidates.length !== 1) return void 0;
|
|
1034
|
+
const candidate = candidates[0];
|
|
1035
|
+
if (candidate === void 0) return void 0;
|
|
1036
|
+
const servicePid = await managedGuardianPid(
|
|
1037
|
+
platform,
|
|
1038
|
+
run,
|
|
1039
|
+
options.uid ?? process.getuid?.() ?? 0
|
|
1040
|
+
);
|
|
1041
|
+
if (servicePid !== void 0 && servicePid !== candidate.pid) return void 0;
|
|
1042
|
+
return isAlive(candidate.pid) ? candidate : void 0;
|
|
1043
|
+
}
|
|
937
1044
|
function isProcessAlive(pid) {
|
|
938
1045
|
try {
|
|
939
1046
|
process.kill(pid, 0);
|
|
@@ -997,9 +1104,9 @@ async function writeFileAtomic(target, data, options = {}) {
|
|
|
997
1104
|
}
|
|
998
1105
|
}
|
|
999
1106
|
async function rmSilently(path) {
|
|
1000
|
-
const { rm:
|
|
1107
|
+
const { rm: rm13 } = await import("fs/promises");
|
|
1001
1108
|
try {
|
|
1002
|
-
await
|
|
1109
|
+
await rm13(path, { force: true });
|
|
1003
1110
|
} catch {
|
|
1004
1111
|
}
|
|
1005
1112
|
}
|
|
@@ -17059,12 +17166,36 @@ function buildSecretHandler(deps) {
|
|
|
17059
17166
|
init_own_package();
|
|
17060
17167
|
|
|
17061
17168
|
// src/guardian/update-handoff.ts
|
|
17062
|
-
import { randomUUID as randomUUID13 } from "crypto";
|
|
17169
|
+
import { createHash as createHash3, randomUUID as randomUUID13 } from "crypto";
|
|
17063
17170
|
import { spawn as spawn7 } from "child_process";
|
|
17064
|
-
import { mkdir as mkdir21, readFile as readFile31 } from "fs/promises";
|
|
17171
|
+
import { chmod, mkdir as mkdir21, readFile as readFile31, rm as rm10 } from "fs/promises";
|
|
17065
17172
|
import { dirname as dirname16, join as join26 } from "path";
|
|
17066
17173
|
init_own_package();
|
|
17067
17174
|
init_process();
|
|
17175
|
+
function guardianUpdateFailureHint(code) {
|
|
17176
|
+
switch (code) {
|
|
17177
|
+
case "filesystem-access":
|
|
17178
|
+
return {
|
|
17179
|
+
zh: "\u66F4\u65B0\u5DE5\u4F5C\u76EE\u5F55\u4E0D\u53EF\u8BBF\u95EE\uFF1B\u8BF7\u53D1\u9001 `/doctor` \u68C0\u67E5\u6587\u4EF6\u6743\u9650\u540E\u91CD\u8BD5\u3002",
|
|
17180
|
+
en: "The private update workspace is inaccessible. Send `/doctor` to check file permissions, then retry."
|
|
17181
|
+
};
|
|
17182
|
+
case "registry-unavailable":
|
|
17183
|
+
return {
|
|
17184
|
+
zh: "\u65E0\u6CD5\u8FDE\u63A5 npm \u6B63\u5F0F\u6E90\uFF1B\u8BF7\u68C0\u67E5\u7F51\u7EDC\u540E\u91CD\u8BD5\u3002",
|
|
17185
|
+
en: "The npm registry is unreachable. Check the network, then retry."
|
|
17186
|
+
};
|
|
17187
|
+
case "bootstrap-unavailable":
|
|
17188
|
+
return {
|
|
17189
|
+
zh: "\u65E0\u6CD5\u542F\u52A8 npm/npx\uFF1B\u8BF7\u53D1\u9001 `/doctor` \u68C0\u67E5 Node.js \u4E0E npm\u3002",
|
|
17190
|
+
en: "npm/npx could not start. Send `/doctor` to check Node.js and npm."
|
|
17191
|
+
};
|
|
17192
|
+
default:
|
|
17193
|
+
return {
|
|
17194
|
+
zh: "\u5347\u7EA7\u547D\u4EE4\u672A\u5B8C\u6210\uFF1B\u8BF7\u53D1\u9001 `/doctor` \u68C0\u67E5\u540E\u91CD\u8BD5\u3002",
|
|
17195
|
+
en: "The upgrade command did not complete. Send `/doctor`, then retry."
|
|
17196
|
+
};
|
|
17197
|
+
}
|
|
17198
|
+
}
|
|
17068
17199
|
async function loadState(file) {
|
|
17069
17200
|
try {
|
|
17070
17201
|
const parsed = JSON.parse(await readFile31(file, "utf8"));
|
|
@@ -17085,6 +17216,36 @@ function validPackageName(value) {
|
|
|
17085
17216
|
function validVersion(value) {
|
|
17086
17217
|
return /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(value);
|
|
17087
17218
|
}
|
|
17219
|
+
async function ensurePrivateDirectory(path) {
|
|
17220
|
+
await mkdir21(path, { recursive: true, mode: 448 });
|
|
17221
|
+
if (process.platform !== "win32") await chmod(path, 448);
|
|
17222
|
+
}
|
|
17223
|
+
function classifyWorkerFailure(code, stdout, stderr) {
|
|
17224
|
+
const output = `${stderr}
|
|
17225
|
+
${stdout}`;
|
|
17226
|
+
if (/\b(?:EACCES|EPERM)\b|permission denied|access is denied/iu.test(output)) {
|
|
17227
|
+
return {
|
|
17228
|
+
errorCode: "filesystem-access",
|
|
17229
|
+
error: "upgrade worker could not access its private working files"
|
|
17230
|
+
};
|
|
17231
|
+
}
|
|
17232
|
+
if (/\b(?:ENOTFOUND|EAI_AGAIN|ECONNREFUSED|ETIMEDOUT)\b|registry unavailable/iu.test(output)) {
|
|
17233
|
+
return {
|
|
17234
|
+
errorCode: "registry-unavailable",
|
|
17235
|
+
error: "upgrade worker could not reach the npm registry"
|
|
17236
|
+
};
|
|
17237
|
+
}
|
|
17238
|
+
if (/\bENOENT\b|not found|not recognized/iu.test(output)) {
|
|
17239
|
+
return {
|
|
17240
|
+
errorCode: "bootstrap-unavailable",
|
|
17241
|
+
error: "upgrade worker could not start the npm bootstrap command"
|
|
17242
|
+
};
|
|
17243
|
+
}
|
|
17244
|
+
return {
|
|
17245
|
+
errorCode: "upgrade-failed",
|
|
17246
|
+
error: `upgrade worker exited with code ${code}`
|
|
17247
|
+
};
|
|
17248
|
+
}
|
|
17088
17249
|
async function defaultLaunch(request) {
|
|
17089
17250
|
const cliPath = join26(ownPackageInfo().root, "dist", "cli.js");
|
|
17090
17251
|
await new Promise((resolve6, reject) => {
|
|
@@ -17120,23 +17281,48 @@ async function runGuardianUpdateWorker(request, options = {}) {
|
|
|
17120
17281
|
if (delayMs > 0) await new Promise((resolve6) => setTimeout(resolve6, delayMs));
|
|
17121
17282
|
const spec = `${state.packageName}@${state.targetVersion}`;
|
|
17122
17283
|
const run = options.run ?? captureOutput;
|
|
17123
|
-
const
|
|
17124
|
-
|
|
17125
|
-
|
|
17126
|
-
|
|
17127
|
-
|
|
17128
|
-
defaultRegistryUrl(),
|
|
17129
|
-
spec,
|
|
17130
|
-
"upgrade",
|
|
17131
|
-
"--profile",
|
|
17132
|
-
state.dshProfile,
|
|
17133
|
-
"--yes",
|
|
17134
|
-
"--restart",
|
|
17135
|
-
"--package",
|
|
17136
|
-
spec
|
|
17137
|
-
],
|
|
17138
|
-
30 * 6e4
|
|
17284
|
+
const workerRoot = join26(dirname16(request.stateFile), "update-worker");
|
|
17285
|
+
const cacheRoot = join26(workerRoot, "npm-cache");
|
|
17286
|
+
const cacheDir = join26(
|
|
17287
|
+
cacheRoot,
|
|
17288
|
+
createHash3("sha256").update(state.id).digest("hex")
|
|
17139
17289
|
);
|
|
17290
|
+
const cwd = join26(workerRoot, "cwd");
|
|
17291
|
+
let result;
|
|
17292
|
+
try {
|
|
17293
|
+
await ensurePrivateDirectory(workerRoot);
|
|
17294
|
+
await rm10(cacheRoot, { recursive: true, force: true });
|
|
17295
|
+
await rm10(cwd, { recursive: true, force: true });
|
|
17296
|
+
await ensurePrivateDirectory(cacheRoot);
|
|
17297
|
+
await ensurePrivateDirectory(cacheDir);
|
|
17298
|
+
await ensurePrivateDirectory(cwd);
|
|
17299
|
+
result = await run(
|
|
17300
|
+
process.platform === "win32" ? "npx.cmd" : "npx",
|
|
17301
|
+
[
|
|
17302
|
+
"--yes",
|
|
17303
|
+
"--cache",
|
|
17304
|
+
cacheDir,
|
|
17305
|
+
"--registry",
|
|
17306
|
+
defaultRegistryUrl(),
|
|
17307
|
+
spec,
|
|
17308
|
+
"upgrade",
|
|
17309
|
+
"--profile",
|
|
17310
|
+
state.dshProfile,
|
|
17311
|
+
"--yes",
|
|
17312
|
+
"--restart",
|
|
17313
|
+
"--package",
|
|
17314
|
+
spec
|
|
17315
|
+
],
|
|
17316
|
+
30 * 6e4,
|
|
17317
|
+
{ cwd, umask: 63 }
|
|
17318
|
+
);
|
|
17319
|
+
} catch (error) {
|
|
17320
|
+
result = {
|
|
17321
|
+
code: 1,
|
|
17322
|
+
stdout: "",
|
|
17323
|
+
stderr: error instanceof Error ? `${error.name}: ${error.message}` : "unknown worker failure"
|
|
17324
|
+
};
|
|
17325
|
+
}
|
|
17140
17326
|
const latest = await loadState(request.stateFile);
|
|
17141
17327
|
if (!latest || latest.id !== request.id) return;
|
|
17142
17328
|
if (latest.status === "succeeded") return;
|
|
@@ -17145,7 +17331,7 @@ async function runGuardianUpdateWorker(request, options = {}) {
|
|
|
17145
17331
|
status: result.code === 0 ? "succeeded" : "failed",
|
|
17146
17332
|
finishedAt: (options.now ?? (() => /* @__PURE__ */ new Date()))().toISOString(),
|
|
17147
17333
|
delivered: false,
|
|
17148
|
-
...result.code === 0 ? {} :
|
|
17334
|
+
...result.code === 0 ? {} : classifyWorkerFailure(result.code, result.stdout, result.stderr)
|
|
17149
17335
|
};
|
|
17150
17336
|
await saveState(request.stateFile, finished);
|
|
17151
17337
|
}
|
|
@@ -17913,12 +18099,13 @@ async function startBridgeEngine(options) {
|
|
|
17913
18099
|
const deliverUpdateResult = async () => {
|
|
17914
18100
|
await updateHandoff.deliverResult(async (state) => {
|
|
17915
18101
|
if (!streaming) throw new Error("channel is not ready");
|
|
18102
|
+
const failureHint = guardianUpdateFailureHint(state.errorCode);
|
|
17916
18103
|
const markdown2 = state.status === "succeeded" ? bilingualMarkdown(
|
|
17917
18104
|
`\u2705 dsh-lark-bot \u5DF2\u66F4\u65B0\u5230 \`${state.targetVersion}\`\uFF0C\u673A\u5668\u4EBA\u5DF2\u5B8C\u6210\u91CD\u8F7D\u3002`,
|
|
17918
18105
|
`\u2705 dsh-lark-bot was updated to \`${state.targetVersion}\` and reloaded.`
|
|
17919
18106
|
) : bilingualMarkdown(
|
|
17920
|
-
`\u26A0\uFE0F dsh-lark-bot \u66F4\u65B0\u5230 \`${state.targetVersion}\` \u5931\u8D25\u3002
|
|
17921
|
-
`\u26A0\uFE0F Failed to update dsh-lark-bot to \`${state.targetVersion}\`.
|
|
18107
|
+
`\u26A0\uFE0F dsh-lark-bot \u66F4\u65B0\u5230 \`${state.targetVersion}\` \u5931\u8D25\u3002${failureHint.zh}`,
|
|
18108
|
+
`\u26A0\uFE0F Failed to update dsh-lark-bot to \`${state.targetVersion}\`. ${failureHint.en}`
|
|
17922
18109
|
);
|
|
17923
18110
|
await streaming.sendMarkdown(state.route.chatId, markdown2, {
|
|
17924
18111
|
...state.route.threadId ? { threadId: state.route.threadId } : {}
|
|
@@ -18310,11 +18497,11 @@ async function restartProfileProcess(profile, options = {}) {
|
|
|
18310
18497
|
// src/upgrade/runtime.ts
|
|
18311
18498
|
init_own_package();
|
|
18312
18499
|
import { existsSync as existsSync7, readFileSync as readFileSync5 } from "fs";
|
|
18313
|
-
import { mkdir as mkdir24, rm as
|
|
18500
|
+
import { mkdir as mkdir24, rm as rm11, symlink } from "fs/promises";
|
|
18314
18501
|
import { join as join29 } from "path";
|
|
18315
18502
|
init_acp_runtime();
|
|
18316
18503
|
async function defaultRelink(linkPath, target) {
|
|
18317
|
-
await
|
|
18504
|
+
await rm11(linkPath, { recursive: true, force: true });
|
|
18318
18505
|
await mkdir24(join29(linkPath, ".."), { recursive: true });
|
|
18319
18506
|
await symlink(target, linkPath, process.platform === "win32" ? "junction" : "dir");
|
|
18320
18507
|
}
|
|
@@ -20055,7 +20242,7 @@ async function uninstallGuardianCommand(options = {}) {
|
|
|
20055
20242
|
const result = await uninstallGuardian({ env });
|
|
20056
20243
|
printResult(result);
|
|
20057
20244
|
}
|
|
20058
|
-
async function statusGuardianCommand(options = {}) {
|
|
20245
|
+
async function statusGuardianCommand(options = {}, deps = {}) {
|
|
20059
20246
|
const env = envWithOverrides(options);
|
|
20060
20247
|
const paths = resolveAppPaths(env.home);
|
|
20061
20248
|
const fallback = newGuardianState({
|
|
@@ -20066,6 +20253,7 @@ async function statusGuardianCommand(options = {}) {
|
|
|
20066
20253
|
const layout = guardianLayoutFor(env, state.bridgeProfile);
|
|
20067
20254
|
const heartbeat = await readHeartbeat(layout.heartbeatFile);
|
|
20068
20255
|
const processFound = await findProfileProcess(state.dshProfile);
|
|
20256
|
+
const guardianProcess = await (deps.findGuardianProcess ?? findGuardianProcess)();
|
|
20069
20257
|
const up = isHeartbeatFresh(heartbeat, env.guardianStaleMs) || processFound !== void 0;
|
|
20070
20258
|
printLines([
|
|
20071
20259
|
"\u5B89\u5168\u7F51\u5B88\u62A4\u72B6\u6001",
|
|
@@ -20077,7 +20265,7 @@ async function statusGuardianCommand(options = {}) {
|
|
|
20077
20265
|
`dsh \u662F\u5426\u5728\u7EBF\uFF1A${up ? "\u662F" : "\u5426"}${processFound ? `\uFF08pid ${processFound.pid}\uFF09` : ""}`,
|
|
20078
20266
|
`\u5FC3\u8DF3\u9F84\uFF1A${heartbeat ? `${heartbeatAgeMs(heartbeat)}ms` : "\u65E0"}`,
|
|
20079
20267
|
`\u5DF2\u89C2\u5BDF\u8FC7 dsh \u8FD0\u884C\uFF1A${state.profileSeenUp ? "\u662F" : "\u5426"}`,
|
|
20080
|
-
"\u5B88\u62A4\u8FDB\u7A0B pid\uFF1A\u672A\u53D1\u73B0\uFF08\
|
|
20268
|
+
guardianProcess === void 0 ? "\u5B88\u62A4\u8FDB\u7A0B pid\uFF1A\u672A\u53D1\u73B0\uFF08\u65E0\u6CD5\u552F\u4E00\u8BC1\u660E resident guardian \u8EAB\u4EFD\uFF09" : `\u5B88\u62A4\u8FDB\u7A0B pid\uFF1A${guardianProcess.pid}`,
|
|
20081
20269
|
`\u72B6\u6001\u6587\u4EF6\uFF1A${layout.stateFile}`,
|
|
20082
20270
|
`\u5FC3\u8DF3\u6587\u4EF6\uFF1A${layout.heartbeatFile}`
|
|
20083
20271
|
]);
|
|
@@ -20320,7 +20508,7 @@ async function runServiceRuntime(options = {}, deps = {}) {
|
|
|
20320
20508
|
// src/cli/commands/bot.ts
|
|
20321
20509
|
init_dsh_runtime();
|
|
20322
20510
|
import { homedir as homedir24 } from "os";
|
|
20323
|
-
import { rm as
|
|
20511
|
+
import { rm as rm12 } from "fs/promises";
|
|
20324
20512
|
import { join as join34 } from "path";
|
|
20325
20513
|
async function runBotCommand(action, options = {}, deps = {}) {
|
|
20326
20514
|
const output = deps.output ?? ((text) => process.stdout.write(text));
|
|
@@ -20379,7 +20567,7 @@ ${rows.join("\n")}
|
|
|
20379
20567
|
current.dshProfile,
|
|
20380
20568
|
instanceEnv(sourceEnv, name, current.dshHome)
|
|
20381
20569
|
).uninstall();
|
|
20382
|
-
await
|
|
20570
|
+
await rm12(join34(paths.botDshHome(name), ".credentials.yaml"), { force: true });
|
|
20383
20571
|
await configs.removeProfile(current.bridgeProfile);
|
|
20384
20572
|
await fleet.remove(name);
|
|
20385
20573
|
output(
|
|
@@ -20416,7 +20604,7 @@ ${rows.join("\n")}
|
|
|
20416
20604
|
} catch (error) {
|
|
20417
20605
|
try {
|
|
20418
20606
|
await service.uninstall();
|
|
20419
|
-
await
|
|
20607
|
+
await rm12(join34(dshHome, ".credentials.yaml"), { force: true });
|
|
20420
20608
|
await fleet.remove(name);
|
|
20421
20609
|
await configs.removeProfile(name);
|
|
20422
20610
|
} catch (cleanupError) {
|