@modelzen/feishu-codex-bridge 0.6.7-test.2 → 0.6.7-test.4
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 +253 -17
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -5716,6 +5716,8 @@ var DM = {
|
|
|
5716
5716
|
coffeeSettings: "dm.coffee.settings",
|
|
5717
5717
|
doctor: "dm.doctor",
|
|
5718
5718
|
reconnect: "dm.reconnect",
|
|
5719
|
+
restart: "dm.restart",
|
|
5720
|
+
restartDo: "dm.restart.do",
|
|
5719
5721
|
update: "dm.update",
|
|
5720
5722
|
updateDo: "dm.update.do",
|
|
5721
5723
|
// 📊 Codex 用量(限额 + 个人资料统计 + 热力图);share 打开内容选择卡,
|
|
@@ -5793,7 +5795,7 @@ function buildDmMenuCard(opts = {}) {
|
|
|
5793
5795
|
actionsFixed([
|
|
5794
5796
|
button("\u{1F4CA} \u7528\u91CF", { a: DM.usage }),
|
|
5795
5797
|
button("\u{1FA7A} \u8BCA\u65AD", { a: DM.doctor }),
|
|
5796
|
-
button("\u{
|
|
5798
|
+
button("\u{1F501} \u91CD\u542F", { a: DM.restart }),
|
|
5797
5799
|
button("\u2B06\uFE0F \u66F4\u65B0", { a: DM.update })
|
|
5798
5800
|
], MENU_BTN_W_BOT),
|
|
5799
5801
|
// 🌐 网页控制台:刻意低调——小号按钮靠左 + 右侧灰字说明;仅在 daemon 本机控制台
|
|
@@ -5910,6 +5912,35 @@ function buildReconnectCard(conn) {
|
|
|
5910
5912
|
{ header: { title: "\u{1F504} \u957F\u8FDE\u63A5", template } }
|
|
5911
5913
|
);
|
|
5912
5914
|
}
|
|
5915
|
+
function buildRestartConfirmCard(conn) {
|
|
5916
|
+
return card(
|
|
5917
|
+
[
|
|
5918
|
+
md(`\u957F\u8FDE\u63A5\u72B6\u6001\uFF1A**${conn}**`),
|
|
5919
|
+
note("\u91CD\u542F\u4F1A**\u65AD\u5F00\u5F53\u524D\u6240\u6709\u4F1A\u8BDD**\u5E76\u91CD\u65B0\u62C9\u8D77\u540E\u53F0\u670D\u52A1\uFF08\u7EA6\u6570\u79D2\uFF0C\u5176\u95F4\u673A\u5668\u4EBA\u77ED\u6682\u79BB\u7EBF\uFF09\uFF0C\u5B8C\u6210\u540E\u81EA\u52A8\u6062\u590D\u3002\u4EC5\u5728\u957F\u671F\u65AD\u8FDE\u6216\u5F02\u5E38\u65F6\u624D\u9700\u8981\u3002"),
|
|
5920
|
+
actions([
|
|
5921
|
+
button("\u{1F501} \u786E\u8BA4\u91CD\u542F", { a: DM.restartDo }, "danger"),
|
|
5922
|
+
button("\u53D6\u6D88", { a: DM.menu })
|
|
5923
|
+
])
|
|
5924
|
+
],
|
|
5925
|
+
{ header: { title: "\u{1F501} \u91CD\u542F\u540E\u53F0\u670D\u52A1", template: "orange" } }
|
|
5926
|
+
);
|
|
5927
|
+
}
|
|
5928
|
+
function buildRestartingCard(mode = "restarting") {
|
|
5929
|
+
if (mode === "foreground") {
|
|
5930
|
+
return card(
|
|
5931
|
+
[
|
|
5932
|
+
md("\u2139\uFE0F \u5F53\u524D\u4E3A**\u524D\u53F0\u8FD0\u884C**\uFF08\u975E\u540E\u53F0\u5B88\u62A4\u670D\u52A1\uFF09\u3002"),
|
|
5933
|
+
note("\u6B64\u6309\u94AE\u53EA\u91CD\u542F\u7531 `feishu-codex-bridge start` \u5B89\u88C5\u7684\u540E\u53F0\u670D\u52A1\u3002\u524D\u53F0\u8FD0\u884C\u8BF7\u5728\u5176\u7EC8\u7AEF\u91CC Ctrl+C \u540E\u91CD\u8DD1 `feishu-codex-bridge run`\u3002"),
|
|
5934
|
+
backToMenu()
|
|
5935
|
+
],
|
|
5936
|
+
{ header: { title: "\u{1F501} \u91CD\u542F\u540E\u53F0\u670D\u52A1", template: "orange" } }
|
|
5937
|
+
);
|
|
5938
|
+
}
|
|
5939
|
+
return card(
|
|
5940
|
+
[md("\u{1F501} \u6B63\u5728\u91CD\u542F\u540E\u53F0\u670D\u52A1\u2026"), note("\u673A\u5668\u4EBA\u5C06\u77ED\u6682\u79BB\u7EBF\u6570\u79D2\u540E\u81EA\u52A8\u6062\u590D\uFF1B\u672C\u5361\u4E0D\u518D\u66F4\u65B0\u3002")],
|
|
5941
|
+
{ header: { title: "\u{1F501} \u91CD\u542F\u540E\u53F0\u670D\u52A1", template: "orange" } }
|
|
5942
|
+
);
|
|
5943
|
+
}
|
|
5913
5944
|
function connLabel(state) {
|
|
5914
5945
|
switch (state) {
|
|
5915
5946
|
case "connected":
|
|
@@ -8509,7 +8540,8 @@ function withCodexHooksFeature(text) {
|
|
|
8509
8540
|
}
|
|
8510
8541
|
|
|
8511
8542
|
// src/service/update.ts
|
|
8512
|
-
|
|
8543
|
+
init_paths();
|
|
8544
|
+
import { closeSync, existsSync as existsSync9, openSync as openSync2, readFileSync as readFileSync4, rmSync as rmSync2, writeFileSync as writeFileSync2, writeSync } from "fs";
|
|
8513
8545
|
import { dirname as dirname10, join as join15, resolve as resolve6 } from "path";
|
|
8514
8546
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
8515
8547
|
|
|
@@ -8800,7 +8832,17 @@ function startNow(opts = {}) {
|
|
|
8800
8832
|
stdio: ["ignore", out, err],
|
|
8801
8833
|
env: mergeProcessEnv(process.env, overrides)
|
|
8802
8834
|
});
|
|
8803
|
-
if (child.pid)
|
|
8835
|
+
if (child.pid) {
|
|
8836
|
+
const pidPath = join13(dir, "service.pid");
|
|
8837
|
+
let cur = null;
|
|
8838
|
+
try {
|
|
8839
|
+
const n = Number.parseInt(readFileSync3(pidPath, "utf8").trim(), 10);
|
|
8840
|
+
cur = Number.isFinite(n) ? n : null;
|
|
8841
|
+
} catch {
|
|
8842
|
+
cur = null;
|
|
8843
|
+
}
|
|
8844
|
+
if (cur === null || !pidAlive(cur)) writeFileSync(pidPath, String(child.pid), "utf8");
|
|
8845
|
+
}
|
|
8804
8846
|
child.unref();
|
|
8805
8847
|
}
|
|
8806
8848
|
async function installWinStartup() {
|
|
@@ -8816,7 +8858,7 @@ async function installWinStartup() {
|
|
|
8816
8858
|
if (reg.status !== 0) {
|
|
8817
8859
|
throw new Error(`\u5199\u5165\u767B\u5F55\u81EA\u542F\u6CE8\u518C\u8868\u9879\u5931\u8D25\uFF08exit ${reg.status ?? "unknown"}\uFF09\uFF1A${(reg.stderr || reg.stdout || "").trim()}`);
|
|
8818
8860
|
}
|
|
8819
|
-
startNow();
|
|
8861
|
+
if (!winStartupRunning()) startNow();
|
|
8820
8862
|
return statusWinStartup();
|
|
8821
8863
|
}
|
|
8822
8864
|
async function uninstallWinStartup() {
|
|
@@ -8885,7 +8927,11 @@ function clearRelaunchClaim(reqPath) {
|
|
|
8885
8927
|
function buildRelauncherPowershell(reqPath, binPath = resolveCliBinPath(), nodePath = process.execPath) {
|
|
8886
8928
|
const inner = `"${nodePath}" "${binPath}" __win-relaunch "${reqPath}"`;
|
|
8887
8929
|
const lit = `'${inner.replace(/'/g, "''")}'`;
|
|
8888
|
-
return
|
|
8930
|
+
return (
|
|
8931
|
+
// Silence the progress stream: with stderr redirected PowerShell serializes
|
|
8932
|
+
// progress records as noisy #< CLIXML blobs into our captured output.
|
|
8933
|
+
`$ProgressPreference='SilentlyContinue'; $c=${lit}; try { $r = Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments @{ CommandLine=$c } -ErrorAction Stop; Write-Output ('cim rv=' + $r.ReturnValue + ' pid=' + $r.ProcessId) } catch { Write-Output ('cim-error: ' + $_.Exception.Message); schtasks /create /tn ${RELAUNCH_TASK_NAME} /tr $c /sc ONCE /st 00:00 /f | Out-Null; $cr=$LASTEXITCODE; schtasks /run /tn ${RELAUNCH_TASK_NAME} | Out-Null; Write-Output ('schtasks create=' + $cr + ' run=' + $LASTEXITCODE) }`
|
|
8934
|
+
);
|
|
8889
8935
|
}
|
|
8890
8936
|
function encodePowershellCommand(script) {
|
|
8891
8937
|
return Buffer.from(script, "utf16le").toString("base64");
|
|
@@ -8983,7 +9029,12 @@ async function runWinRelaunch(deps = {}) {
|
|
|
8983
9029
|
}
|
|
8984
9030
|
await sleep(300);
|
|
8985
9031
|
start({ appDir: appDir2, envPath: req.envPath, userProfile: req.userProfile });
|
|
8986
|
-
|
|
9032
|
+
let newPid = "?";
|
|
9033
|
+
try {
|
|
9034
|
+
newPid = readFileSync3(join13(appDir2, "service.pid"), "utf8").trim() || "?";
|
|
9035
|
+
} catch {
|
|
9036
|
+
}
|
|
9037
|
+
logLine(`relaunched; new daemon pid=${newPid} (appDir=${appDir2})`);
|
|
8987
9038
|
} finally {
|
|
8988
9039
|
clearClaim(reqPath);
|
|
8989
9040
|
if (process.platform === "win32") {
|
|
@@ -9297,6 +9348,84 @@ async function installLatest(opts = {}) {
|
|
|
9297
9348
|
});
|
|
9298
9349
|
});
|
|
9299
9350
|
}
|
|
9351
|
+
var UPDATE_LOCK_STALE_MS = 30 * 60 * 1e3;
|
|
9352
|
+
function updateLockFile() {
|
|
9353
|
+
return join15(paths.appDir, "update.lock");
|
|
9354
|
+
}
|
|
9355
|
+
function livePid(pid) {
|
|
9356
|
+
try {
|
|
9357
|
+
process.kill(pid, 0);
|
|
9358
|
+
return true;
|
|
9359
|
+
} catch (err) {
|
|
9360
|
+
return err.code === "EPERM";
|
|
9361
|
+
}
|
|
9362
|
+
}
|
|
9363
|
+
function isUpdateLockStale(file) {
|
|
9364
|
+
try {
|
|
9365
|
+
const rec = JSON.parse(readFileSync4(file, "utf8"));
|
|
9366
|
+
if (typeof rec.pid !== "number") return true;
|
|
9367
|
+
if (!livePid(rec.pid)) return true;
|
|
9368
|
+
return typeof rec.at === "number" && Date.now() - rec.at > UPDATE_LOCK_STALE_MS;
|
|
9369
|
+
} catch {
|
|
9370
|
+
return true;
|
|
9371
|
+
}
|
|
9372
|
+
}
|
|
9373
|
+
function acquireUpdateLock() {
|
|
9374
|
+
const file = updateLockFile();
|
|
9375
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
9376
|
+
try {
|
|
9377
|
+
const fd = openSync2(file, "wx");
|
|
9378
|
+
writeSync(fd, JSON.stringify({ pid: process.pid, at: Date.now() }));
|
|
9379
|
+
closeSync(fd);
|
|
9380
|
+
return releaseUpdateLock(file);
|
|
9381
|
+
} catch (err) {
|
|
9382
|
+
const code = err.code;
|
|
9383
|
+
if (code !== "EEXIST") return null;
|
|
9384
|
+
if (!isUpdateLockStale(file)) return null;
|
|
9385
|
+
try {
|
|
9386
|
+
rmSync2(file, { force: true });
|
|
9387
|
+
} catch {
|
|
9388
|
+
}
|
|
9389
|
+
}
|
|
9390
|
+
}
|
|
9391
|
+
return null;
|
|
9392
|
+
}
|
|
9393
|
+
function releaseUpdateLock(file) {
|
|
9394
|
+
return () => {
|
|
9395
|
+
try {
|
|
9396
|
+
const rec = JSON.parse(readFileSync4(file, "utf8"));
|
|
9397
|
+
if (rec.pid !== process.pid) return;
|
|
9398
|
+
} catch {
|
|
9399
|
+
}
|
|
9400
|
+
try {
|
|
9401
|
+
rmSync2(file, { force: true });
|
|
9402
|
+
} catch {
|
|
9403
|
+
}
|
|
9404
|
+
};
|
|
9405
|
+
}
|
|
9406
|
+
function updateStatusFile() {
|
|
9407
|
+
return join15(paths.appDir, "update-status.json");
|
|
9408
|
+
}
|
|
9409
|
+
function writeUpdateStatus(status) {
|
|
9410
|
+
try {
|
|
9411
|
+
writeFileSync2(updateStatusFile(), JSON.stringify(status), "utf8");
|
|
9412
|
+
} catch {
|
|
9413
|
+
}
|
|
9414
|
+
}
|
|
9415
|
+
function readUpdateStatus() {
|
|
9416
|
+
try {
|
|
9417
|
+
const s = JSON.parse(readFileSync4(updateStatusFile(), "utf8"));
|
|
9418
|
+
return s && typeof s.phase === "string" && typeof s.at === "number" ? s : null;
|
|
9419
|
+
} catch {
|
|
9420
|
+
return null;
|
|
9421
|
+
}
|
|
9422
|
+
}
|
|
9423
|
+
function clearUpdateStatus() {
|
|
9424
|
+
try {
|
|
9425
|
+
rmSync2(updateStatusFile(), { force: true });
|
|
9426
|
+
} catch {
|
|
9427
|
+
}
|
|
9428
|
+
}
|
|
9300
9429
|
function daemonRunning() {
|
|
9301
9430
|
return isServiceRunning();
|
|
9302
9431
|
}
|
|
@@ -9886,7 +10015,7 @@ function buildUsageShareCard(data, opts = {}) {
|
|
|
9886
10015
|
// src/web/discovery.ts
|
|
9887
10016
|
init_paths();
|
|
9888
10017
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
9889
|
-
import { mkdirSync as mkdirSync2, readFileSync as readFileSync5, unlinkSync, writeFileSync as
|
|
10018
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync5, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
|
|
9890
10019
|
import { dirname as dirname11 } from "path";
|
|
9891
10020
|
function publishWebConsole(rec, file = paths.webConsoleFile) {
|
|
9892
10021
|
mkdirSync2(dirname11(file), { recursive: true });
|
|
@@ -9894,7 +10023,7 @@ function publishWebConsole(rec, file = paths.webConsoleFile) {
|
|
|
9894
10023
|
unlinkSync(file);
|
|
9895
10024
|
} catch {
|
|
9896
10025
|
}
|
|
9897
|
-
|
|
10026
|
+
writeFileSync3(file, `${JSON.stringify(rec, null, 2)}
|
|
9898
10027
|
`, { mode: 384 });
|
|
9899
10028
|
}
|
|
9900
10029
|
function readWebConsole(file = paths.webConsoleFile) {
|
|
@@ -9934,7 +10063,7 @@ function stableWebConsoleToken(file = paths.webTokenFile) {
|
|
|
9934
10063
|
unlinkSync(file);
|
|
9935
10064
|
} catch {
|
|
9936
10065
|
}
|
|
9937
|
-
|
|
10066
|
+
writeFileSync3(file, `${token}
|
|
9938
10067
|
`, { mode: 384 });
|
|
9939
10068
|
} catch {
|
|
9940
10069
|
}
|
|
@@ -12639,6 +12768,24 @@ function createOrchestrator(channel, cfg, fallbackCwd, cliBridge) {
|
|
|
12639
12768
|
await sendManagedCard(channel, evt.chatId, buildReconnectCard(conn), evt.messageId).catch(
|
|
12640
12769
|
(err) => log.fail("console", err, { cmd: "reconnect" })
|
|
12641
12770
|
);
|
|
12771
|
+
}).on(DM.restart, async ({ evt }) => {
|
|
12772
|
+
if (!dmAdmin(evt.operator?.openId)) return;
|
|
12773
|
+
const conn = channel.getConnectionStatus?.()?.state ?? "unknown";
|
|
12774
|
+
await sendManagedCard(channel, evt.chatId, buildRestartConfirmCard(conn), evt.messageId).catch(
|
|
12775
|
+
(err) => log.fail("console", err, { cmd: "restart" })
|
|
12776
|
+
);
|
|
12777
|
+
}).on(DM.restartDo, ({ evt }) => {
|
|
12778
|
+
if (!dmAdmin(evt.operator?.openId)) return;
|
|
12779
|
+
void (async () => {
|
|
12780
|
+
await new Promise((r) => setTimeout(r, CARD_SETTLE_MS));
|
|
12781
|
+
if (!daemonRunning()) {
|
|
12782
|
+
await updateManagedCard(channel, evt.messageId, buildRestartingCard("foreground")).catch(() => void 0);
|
|
12783
|
+
return;
|
|
12784
|
+
}
|
|
12785
|
+
await updateManagedCard(channel, evt.messageId, buildRestartingCard("restarting")).catch(() => void 0);
|
|
12786
|
+
await new Promise((r) => setTimeout(r, 800));
|
|
12787
|
+
await restartDaemon().catch((e) => log.fail("console", e, { phase: "restart" }));
|
|
12788
|
+
})();
|
|
12642
12789
|
}).on(DM.update, ({ evt }) => {
|
|
12643
12790
|
if (!dmAdmin(evt.operator?.openId)) return;
|
|
12644
12791
|
void (async () => {
|
|
@@ -12661,10 +12808,24 @@ function createOrchestrator(channel, cfg, fallbackCwd, cliBridge) {
|
|
|
12661
12808
|
void (async () => {
|
|
12662
12809
|
await new Promise((r) => setTimeout(r, CARD_SETTLE_MS));
|
|
12663
12810
|
const from = currentVersion();
|
|
12811
|
+
const release2 = acquireUpdateLock();
|
|
12812
|
+
if (!release2) {
|
|
12813
|
+
await updateManagedCard(
|
|
12814
|
+
channel,
|
|
12815
|
+
evt.messageId,
|
|
12816
|
+
buildUpdateCard({ phase: "error", from, message: "\u5DF2\u6709\u4E00\u4E2A\u66F4\u65B0\u6B63\u5728\u8FDB\u884C\u4E2D\uFF0C\u8BF7\u7A0D\u5019\u518D\u8BD5\u3002" })
|
|
12817
|
+
).catch(() => void 0);
|
|
12818
|
+
return;
|
|
12819
|
+
}
|
|
12664
12820
|
await updateManagedCard(channel, evt.messageId, buildUpdateCard({ phase: "updating", from })).catch(
|
|
12665
12821
|
() => void 0
|
|
12666
12822
|
);
|
|
12667
|
-
|
|
12823
|
+
let res;
|
|
12824
|
+
try {
|
|
12825
|
+
res = await installLatest();
|
|
12826
|
+
} finally {
|
|
12827
|
+
release2();
|
|
12828
|
+
}
|
|
12668
12829
|
if (!res.ok) {
|
|
12669
12830
|
log.info("console", "update-failed", { from });
|
|
12670
12831
|
await updateManagedCard(
|
|
@@ -13969,6 +14130,9 @@ ${facts}`;
|
|
|
13969
14130
|
case DM.reconnect:
|
|
13970
14131
|
await sendDm(buildReconnectCard(channel.getConnectionStatus?.()?.state ?? "unknown"));
|
|
13971
14132
|
break;
|
|
14133
|
+
case DM.restart:
|
|
14134
|
+
await sendDm(buildRestartConfirmCard(channel.getConnectionStatus?.()?.state ?? "unknown"));
|
|
14135
|
+
break;
|
|
13972
14136
|
case DM.usage: {
|
|
13973
14137
|
const { messageId } = await sendDm(buildUsageCard({ phase: "loading" }));
|
|
13974
14138
|
let state;
|
|
@@ -14683,8 +14847,12 @@ function createAdminService(deps = {}) {
|
|
|
14683
14847
|
dev: false
|
|
14684
14848
|
}));
|
|
14685
14849
|
},
|
|
14850
|
+
updateStatus() {
|
|
14851
|
+
return readUpdateStatus();
|
|
14852
|
+
},
|
|
14686
14853
|
async applyUpdate() {
|
|
14687
14854
|
if (!deps.applyUpdate) throw new NotWiredYetError("\u2B06\uFE0F \u5347\u7EA7");
|
|
14855
|
+
clearUpdateStatus();
|
|
14688
14856
|
deps.applyUpdate();
|
|
14689
14857
|
},
|
|
14690
14858
|
async hostDoctor() {
|
|
@@ -14912,14 +15080,31 @@ async function doUpdate() {
|
|
|
14912
15080
|
log.info("daemon-control", "update-skipped-dev", {});
|
|
14913
15081
|
return;
|
|
14914
15082
|
}
|
|
14915
|
-
const
|
|
15083
|
+
const release2 = acquireUpdateLock();
|
|
15084
|
+
if (!release2) {
|
|
15085
|
+
log.info("daemon-control", "update-skipped-in-progress", {});
|
|
15086
|
+
appendServiceErr("daemon-control", "update already in progress (lock held by another trigger); skipped");
|
|
15087
|
+
return;
|
|
15088
|
+
}
|
|
15089
|
+
const from = currentVersion();
|
|
15090
|
+
writeUpdateStatus({ phase: "installing", from, at: Date.now() });
|
|
15091
|
+
let res;
|
|
15092
|
+
try {
|
|
15093
|
+
res = await installLatest();
|
|
15094
|
+
} finally {
|
|
15095
|
+
release2();
|
|
15096
|
+
}
|
|
14916
15097
|
log.info("daemon-control", "update-installed", { ok: res.ok });
|
|
14917
15098
|
appendServiceErr("daemon-control", `update-installed ok=${res.ok}`);
|
|
14918
15099
|
if (!res.ok) {
|
|
14919
15100
|
appendServiceErr("daemon-control", "install failed \u2014 keeping old version, not restarting");
|
|
15101
|
+
writeUpdateStatus({ phase: "error", ok: false, from, message: `\u5B89\u88C5\u5931\u8D25\uFF1A${res.message}`.slice(0, 300), at: Date.now() });
|
|
14920
15102
|
return;
|
|
14921
15103
|
}
|
|
15104
|
+
const to = currentVersion();
|
|
15105
|
+
writeUpdateStatus({ phase: "restarting", ok: true, from, to, at: Date.now() });
|
|
14922
15106
|
await doRestart("update");
|
|
15107
|
+
writeUpdateStatus({ phase: "done", ok: true, from, to, at: Date.now() });
|
|
14923
15108
|
}
|
|
14924
15109
|
async function doRestart(phase) {
|
|
14925
15110
|
if (!isServiceRunning()) {
|
|
@@ -15681,6 +15866,7 @@ ${UI_PURE_JS}
|
|
|
15681
15866
|
var lastUpdate = null; // /api/update/check \u7ED3\u679C\u7F13\u5B58\uFF1A\u603B\u89C8 5s \u91CD\u6E32\u4E0D\u91CD\u67E5\uFF08\u6BCF\u6B21\u67E5\u90FD spawn npm view\uFF09
|
|
15682
15867
|
var updateCheckedAt = 0; // \u4E0A\u6B21\u68C0\u67E5\u65F6\u95F4\u6233\uFF1B\u62FF\u5230\u7ED3\u679C\u8D85 30min\u3001\u8F6F\u5931\u8D25\u8D85 ~2min \u624D\u968F\u91CD\u6E32\u81EA\u52A8\u590D\u67E5
|
|
15683
15868
|
var updateChecking = false;// in-flight \u95F8\uFF1Anpm view \u53EF\u80FD\u6570\u79D2~20s\uFF0C\u671F\u95F4 5s \u91CD\u6E32\u4E0D\u53E0\u53D1\u7B2C\u4E8C\u4E2A\u8BF7\u6C42
|
|
15869
|
+
var updateInFlight = false; // \u300C\u5347\u7EA7\u5E76\u91CD\u542F\u300Din-flight\uFF1A\u7981\u7528\u6309\u94AE\u9632\u91CD\u590D\u70B9\u51FB\uFF08\u5E76\u53D1\u89E6\u53D1\u4F1A\u7ED5\u8FC7\u670D\u52A1\u7AEF\u66F4\u65B0\u9501\u7684\u7A84\u7A97\uFF09\uFF0C\u5E76\u9A71\u52A8\u8F6E\u8BE2\u7ED3\u679C
|
|
15684
15870
|
var drawerProject = null; // \u62BD\u5C49\u91CC\u6253\u5F00\u7684\u9879\u76EE\u540D
|
|
15685
15871
|
var diagBotId = null; // diag \u5C5E\u4E8E\u54EA\u4E2A bot\uFF08\u9632\u4E32\u53F0\uFF09
|
|
15686
15872
|
var bkDetailId = null; // \u540E\u7AEF Agent \u8BE6\u60C5\u89C6\u56FE\u5F53\u524D\u5C55\u5F00\u7684\u540E\u7AEF id\uFF08null=\u5217\u8868\uFF09
|
|
@@ -16590,10 +16776,13 @@ ${UI_PURE_JS}
|
|
|
16590
16776
|
if (u.hasUpdate && u.latest) {
|
|
16591
16777
|
box.appendChild(el('div', null, '\u{1F195} \u6709\u65B0\u7248 v' + u.latest + '\uFF08\u5F53\u524D v' + u.current + '\uFF09'));
|
|
16592
16778
|
var row = el('div', 'statline');
|
|
16593
|
-
|
|
16594
|
-
|
|
16779
|
+
// updateInFlight \u671F\u95F4\u663E\u793A\u7981\u7528\u7684\u300C\u66F4\u65B0\u4E2D\u2026\u300D\u2014\u2014\u5373\u4F7F\u5361\u7247\u6BCF 5s \u91CD\u6E32\uFF0C\u6309\u94AE\u4E5F\u4FDD\u6301\u7981\u7528\uFF0C
|
|
16780
|
+
// \u6321\u4F4F\u91CD\u590D\u63D0\u4EA4\uFF08\u91CD\u590D\u89E6\u53D1\u662F\u5E76\u53D1\u7ED5\u8FC7\u670D\u52A1\u7AEF\u66F4\u65B0\u9501\u7684\u5165\u53E3\uFF09\u3002
|
|
16781
|
+
var up = el('button', 'btn primary', updateInFlight ? '\u23F3 \u66F4\u65B0\u4E2D\u2026' : ('\u2B06\uFE0F \u66F4\u65B0\u5E76\u91CD\u542F \xB7 v' + u.latest));
|
|
16782
|
+
if (updateInFlight) { up.disabled = true; }
|
|
16783
|
+
else { up.onclick = function () { askUpdate(u.latest); }; }
|
|
16595
16784
|
row.appendChild(up);
|
|
16596
|
-
row.appendChild(el('span', 'note', '\u9ED8\u8BA4\u53EA\u68C0\u6D4B\u4E0D\u81EA\u52A8\u5347\u7EA7\uFF1B\u70B9\u4E0A\u65B9\u6309\u94AE\u88C5\u6700\u65B0\u7248\u5E76\u81EA\u52A8\u91CD\u542F\u3002'));
|
|
16785
|
+
row.appendChild(el('span', 'note', updateInFlight ? '\u5B89\u88C5\u4E2D\uFF0C\u5B8C\u6210\u540E\u4F1A\u81EA\u52A8\u91CD\u542F\u2026' : '\u9ED8\u8BA4\u53EA\u68C0\u6D4B\u4E0D\u81EA\u52A8\u5347\u7EA7\uFF1B\u70B9\u4E0A\u65B9\u6309\u94AE\u88C5\u6700\u65B0\u7248\u5E76\u81EA\u52A8\u91CD\u542F\u3002'));
|
|
16597
16786
|
box.appendChild(row);
|
|
16598
16787
|
} else {
|
|
16599
16788
|
box.appendChild(el('div', 'note', '\u2705 \u5DF2\u662F\u6700\u65B0\u7248 v' + u.current + (u.latest ? '' : '\uFF08\u6700\u65B0\u7248\u67E5\u8BE2\u5931\u8D25\uFF0C\u53EF\u7A0D\u540E\u91CD\u8BD5\uFF09')));
|
|
@@ -16643,9 +16832,52 @@ ${UI_PURE_JS}
|
|
|
16643
16832
|
'\u91CD\u542F\u671F\u95F4\u6240\u6709\u7FA4\u77ED\u6682\u65E0\u54CD\u5E94\uFF1B\u6B63\u5728\u8FDB\u884C\u7684\u4F1A\u8BDD\u4F1A\u88AB\u4F18\u96C5\u5173\u95ED\u3002',
|
|
16644
16833
|
],
|
|
16645
16834
|
confirmLabel: '\u786E\u8BA4\u66F4\u65B0',
|
|
16646
|
-
onConfirm: function () {
|
|
16835
|
+
onConfirm: function () { postUpdate(latest); },
|
|
16647
16836
|
});
|
|
16648
16837
|
}
|
|
16838
|
+
// \u5347\u7EA7\uFF1APOST \u540E\u8F6E\u8BE2 /api/update/status\uFF0C\u5931\u8D25\u4F1A\u660E\u786E\u62A5\u51FA\u6765\uFF08\u5426\u5219 detached helper \u7684\u5931\u8D25\u5BF9
|
|
16839
|
+
// \u7F51\u9875\u7AEF\u5B8C\u5168\u9759\u9ED8\u3001\u7528\u6237\u53EA\u770B\u5230\u300C\u5DF2\u53D1\u8D77\u300D\uFF09\uFF1B\u6210\u529F\u4F1A\u91CD\u542F daemon \u2192 \u8FDE\u63A5\u77ED\u6682\u65AD\u5F00\uFF0C\u7531\u7248\u672C\u53D8\u66F4\u6D41
|
|
16840
|
+
// \u63A5\u7BA1\u663E\u793A\u300C\u5DF2\u662F\u6700\u65B0\u7248\u300D\u3002updateInFlight \u517C\u4F5C\u6309\u94AE in-flight \u95F8\uFF0C\u6321\u4F4F\u91CD\u590D\u70B9\u51FB\u3002
|
|
16841
|
+
function postUpdate(latest) {
|
|
16842
|
+
if (updateInFlight) { toast('\u23F3 \u5347\u7EA7\u5DF2\u5728\u8FDB\u884C\u4E2D\u2026'); return; }
|
|
16843
|
+
updateInFlight = true;
|
|
16844
|
+
var box = $('updateBody'); if (box && lastUpdate) renderUpdate(box, lastUpdate); // \u7ACB\u523B\u628A\u6309\u94AE\u5207\u6210\u7981\u7528\u7684\u300C\u66F4\u65B0\u4E2D\u2026\u300D
|
|
16845
|
+
fetch('/api/update', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{}' })
|
|
16846
|
+
.then(function (r) { return r.json().then(function (j) { return { status: r.status, body: j }; }); })
|
|
16847
|
+
.then(function (resp) {
|
|
16848
|
+
if (resp.status !== 202) {
|
|
16849
|
+
updateInFlight = false;
|
|
16850
|
+
toast((resp.status === 501 ? '\u23F3 ' : '\u274C ') + (resp.body.message || ('HTTP ' + resp.status)));
|
|
16851
|
+
var b = $('updateBody'); if (b) loadUpdate(b);
|
|
16852
|
+
return;
|
|
16853
|
+
}
|
|
16854
|
+
toast('\u2705 ' + (resp.body.message || '\u5347\u7EA7\u5DF2\u53D1\u8D77'));
|
|
16855
|
+
pollUpdateStatus(0, latest);
|
|
16856
|
+
})
|
|
16857
|
+
.catch(function () { updateInFlight = false; toast('\u274C \u8BF7\u6C42\u5931\u8D25'); });
|
|
16858
|
+
}
|
|
16859
|
+
function pollUpdateStatus(tries, latest) {
|
|
16860
|
+
if (tries > 60) { updateInFlight = false; toast('\u23F3 \u5B89\u88C5\u4ECD\u5728\u540E\u53F0\u8FDB\u884C\uFF0C\u7A0D\u540E\u5237\u65B0\u9875\u9762\u67E5\u770B'); return; } // ~90s \u515C\u5E95\uFF1A\u522B\u65E0\u9650\u8F6E\u8BE2
|
|
16861
|
+
fetch('/api/update/status').then(function (r) { return r.json(); })
|
|
16862
|
+
.then(function (s) {
|
|
16863
|
+
if (!s || s.phase === 'installing' || s.phase === 'restarting') {
|
|
16864
|
+
setTimeout(function () { pollUpdateStatus(tries + 1, latest); }, 1500);
|
|
16865
|
+
return;
|
|
16866
|
+
}
|
|
16867
|
+
updateInFlight = false;
|
|
16868
|
+
if (s.phase === 'error') {
|
|
16869
|
+
toast('\u274C \u5347\u7EA7\u5931\u8D25\uFF1A' + (s.message || '\u672A\u77E5\u9519\u8BEF'));
|
|
16870
|
+
var box = $('updateBody'); if (box) loadUpdate(box); // \u6062\u590D\u53EF\u70B9\u7684\u66F4\u65B0\u5361\u4F9B\u91CD\u8BD5
|
|
16871
|
+
} else if (s.phase === 'done') {
|
|
16872
|
+
toast('\u2705 \u5DF2\u66F4\u65B0\u5230 v' + (s.to || latest || '') + '\uFF0C\u6B63\u5728\u91CD\u542F\u2026');
|
|
16873
|
+
lastUpdate = null; updateCheckedAt = 0; // \u4F5C\u5E9F\u7F13\u5B58\uFF1A\u91CD\u542F\u540E\u7248\u672C\u53D8\u66F4\u6D41\u4F1A\u7FFB\u6210\u300C\u5DF2\u662F\u6700\u65B0\u7248\u300D
|
|
16874
|
+
}
|
|
16875
|
+
})
|
|
16876
|
+
.catch(function () {
|
|
16877
|
+
// \u62FF\u4E0D\u5230\u72B6\u6001\uFF1A\u591A\u534A daemon \u6B63\u5728\u91CD\u542F\uFF08\u6210\u529F\u8DEF\u5F84\uFF09\u2192 \u4EA4\u7ED9\u91CD\u8FDE/\u7248\u672C\u53D8\u66F4\u6D41\u6536\u5C3E\u3002
|
|
16878
|
+
updateInFlight = false;
|
|
16879
|
+
});
|
|
16880
|
+
}
|
|
16649
16881
|
// 202 = \u5DF2\u53D1\u8D77\uFF08detached helper \u63A5\u7BA1\uFF09\uFF1B501 = \u53EA\u8BFB\u9884\u89C8\uFF08\u65E0 daemon\uFF09\u3002
|
|
16650
16882
|
function postAction(path, label) {
|
|
16651
16883
|
fetch(path, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{}' })
|
|
@@ -17772,6 +18004,10 @@ function createWebServer(opts) {
|
|
|
17772
18004
|
sendJson(res, 200, await opts.service.checkUpdate());
|
|
17773
18005
|
return;
|
|
17774
18006
|
}
|
|
18007
|
+
if (req.method === "GET" && pathName === "/api/update/status") {
|
|
18008
|
+
sendJson(res, 200, opts.service.updateStatus());
|
|
18009
|
+
return;
|
|
18010
|
+
}
|
|
17775
18011
|
if (req.method === "POST" && pathName === "/api/update") {
|
|
17776
18012
|
try {
|
|
17777
18013
|
await opts.service.applyUpdate();
|
|
@@ -18485,7 +18721,7 @@ async function runSupervisor(bots) {
|
|
|
18485
18721
|
|
|
18486
18722
|
// src/core/single-instance.ts
|
|
18487
18723
|
init_paths();
|
|
18488
|
-
import { mkdirSync as mkdirSync4, readFileSync as readFileSync6, statSync as statSync3, unlinkSync as unlinkSync2, writeFileSync as
|
|
18724
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync6, statSync as statSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
18489
18725
|
import { dirname as dirname15 } from "path";
|
|
18490
18726
|
var CLAIM_ATTEMPTS = 5;
|
|
18491
18727
|
var PID_REUSE_SLACK_MS = 15e3;
|
|
@@ -18536,7 +18772,7 @@ function acquireSingleInstanceLock(appId, file = paths.processesFile) {
|
|
|
18536
18772
|
const record = { pid: process.pid, appId, startedAt: Date.now() };
|
|
18537
18773
|
for (let attempt = 0; attempt < CLAIM_ATTEMPTS; attempt++) {
|
|
18538
18774
|
try {
|
|
18539
|
-
|
|
18775
|
+
writeFileSync4(file, `${JSON.stringify(record)}
|
|
18540
18776
|
`, { flag: "wx" });
|
|
18541
18777
|
const release2 = () => {
|
|
18542
18778
|
try {
|
package/package.json
CHANGED