@modelzen/feishu-codex-bridge 0.3.12-test.0 → 0.3.12-test.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 +105 -87
- package/dist/index.d.ts +3 -0
- package/dist/index.js +4 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -91,7 +91,10 @@ var paths = {
|
|
|
91
91
|
inboundDir: join(appDir, "inbound"),
|
|
92
92
|
/** daemon 内嵌 Web 控制台的发现文件 {port, token, pid}(0600,daemon 退出
|
|
93
93
|
* 清理)——`web` 子命令据此直接打开 daemon 控制台而不是再起只读副本。 */
|
|
94
|
-
webConsoleFile: join(appDir, "web-console.json")
|
|
94
|
+
webConsoleFile: join(appDir, "web-console.json"),
|
|
95
|
+
/** 稳定的 Web 控制台 token(0600,**不随进程退出清理**)——让重启 / 预览→daemon
|
|
96
|
+
* 切换后浏览器里那条带 token 的 URL 始终有效,不再 401。删此文件即轮换 token。 */
|
|
97
|
+
webTokenFile: join(appDir, "web-token")
|
|
95
98
|
};
|
|
96
99
|
|
|
97
100
|
// src/config/bots.ts
|
|
@@ -12167,7 +12170,7 @@ async function catalogEntryStatus(entry, defaultBackend) {
|
|
|
12167
12170
|
}
|
|
12168
12171
|
async function probeAllBackends() {
|
|
12169
12172
|
return Promise.all(
|
|
12170
|
-
|
|
12173
|
+
visibleCatalog().map((e) => e.id).map(async (id) => {
|
|
12171
12174
|
const backend = createBackend(id);
|
|
12172
12175
|
const probe = await backend.doctor({ force: true }).catch(() => void 0);
|
|
12173
12176
|
return {
|
|
@@ -12195,6 +12198,7 @@ function isAlive(pid) {
|
|
|
12195
12198
|
}
|
|
12196
12199
|
|
|
12197
12200
|
// src/web/discovery.ts
|
|
12201
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
12198
12202
|
import { mkdirSync as mkdirSync2, readFileSync as readFileSync5, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
12199
12203
|
import { dirname as dirname12 } from "path";
|
|
12200
12204
|
function publishWebConsole(rec, file = paths.webConsoleFile) {
|
|
@@ -12225,6 +12229,25 @@ function clearWebConsole(file = paths.webConsoleFile) {
|
|
|
12225
12229
|
} catch {
|
|
12226
12230
|
}
|
|
12227
12231
|
}
|
|
12232
|
+
function stableWebConsoleToken(file = paths.webTokenFile) {
|
|
12233
|
+
try {
|
|
12234
|
+
const t = readFileSync5(file, "utf8").trim();
|
|
12235
|
+
if (t) return t;
|
|
12236
|
+
} catch {
|
|
12237
|
+
}
|
|
12238
|
+
const token = randomUUID6();
|
|
12239
|
+
try {
|
|
12240
|
+
mkdirSync2(dirname12(file), { recursive: true });
|
|
12241
|
+
try {
|
|
12242
|
+
unlinkSync(file);
|
|
12243
|
+
} catch {
|
|
12244
|
+
}
|
|
12245
|
+
writeFileSync2(file, `${token}
|
|
12246
|
+
`, { mode: 384 });
|
|
12247
|
+
} catch {
|
|
12248
|
+
}
|
|
12249
|
+
return token;
|
|
12250
|
+
}
|
|
12228
12251
|
function isAlive2(pid) {
|
|
12229
12252
|
try {
|
|
12230
12253
|
process.kill(pid, 0);
|
|
@@ -12347,7 +12370,7 @@ async function doRestart(phase) {
|
|
|
12347
12370
|
|
|
12348
12371
|
// src/web/server.ts
|
|
12349
12372
|
import { createServer } from "http";
|
|
12350
|
-
import { randomUUID as
|
|
12373
|
+
import { randomUUID as randomUUID7, timingSafeEqual } from "crypto";
|
|
12351
12374
|
import { mkdirSync as mkdirSync3, watch } from "fs";
|
|
12352
12375
|
import { open as open2, stat as stat5 } from "fs/promises";
|
|
12353
12376
|
import { join as join19 } from "path";
|
|
@@ -14368,7 +14391,7 @@ ${UI_PURE_JS}
|
|
|
14368
14391
|
box.textContent = '';
|
|
14369
14392
|
box.className = 'note';
|
|
14370
14393
|
if (!diag) return;
|
|
14371
|
-
box.appendChild(el('div', null, '\u4E8B\u4EF6\u8BA2\u9605\uFF1A
|
|
14394
|
+
box.appendChild(el('div', null, '\u2139\uFE0F \u4E8B\u4EF6\u8BA2\u9605\uFF1A\u8BF7\u81EA\u884C\u5230\u300C\u4E8B\u4EF6\u4E0E\u56DE\u8C03\u300D\u786E\u8BA4\u5DF2\u8BA2\u9605 im.message.receive_v1\uFF08\u957F\u8FDE\u63A5\uFF09\uFF1B\u6B64\u9879\u7CFB\u7EDF\u65E0\u6CD5\u53EF\u9760\u68C0\u6D4B\uFF0C\u4EC5\u4F5C\u63D0\u9192\u3002'));
|
|
14372
14395
|
var title = el('div', null, '\u{1F9E0} \u540E\u7AEF\u73AF\u5883\uFF1A');
|
|
14373
14396
|
title.style.marginTop = '6px';
|
|
14374
14397
|
box.appendChild(title);
|
|
@@ -14553,9 +14576,12 @@ ${UI_PURE_JS}
|
|
|
14553
14576
|
var wizEs = null; // \u626B\u7801 SSE EventSource
|
|
14554
14577
|
var wizQrSessionId = null;
|
|
14555
14578
|
var wizCountdown = null; // \u4E8C\u7EF4\u7801\u8FC7\u671F\u5012\u8BA1\u65F6
|
|
14579
|
+
var wizAutoEnabled = false; // \u65B0 bot \u662F\u5426\u5DF2\u81EA\u52A8\u52A0\u5165\u6D3B\u8DC3\u96C6\uFF08\u4E00\u6B21\u6027\uFF09
|
|
14580
|
+
var wizRestartPrompted = false; // \u5B8C\u6210\u6B65\u662F\u5426\u5DF2\u5F39\u8FC7\u300C\u91CD\u542F\u62C9\u8D77\u300D\u786E\u8BA4\uFF08\u4E00\u6B21\u6027\uFF09
|
|
14556
14581
|
|
|
14557
14582
|
function openWizard() {
|
|
14558
14583
|
wizStep = 1; wizBotId = null; wizSetup = null; wizManualOpen = false;
|
|
14584
|
+
wizAutoEnabled = false; wizRestartPrompted = false;
|
|
14559
14585
|
stopWizPoll(); stopWizQr();
|
|
14560
14586
|
$('wizMask').classList.add('open');
|
|
14561
14587
|
renderWizard();
|
|
@@ -14773,12 +14799,21 @@ ${UI_PURE_JS}
|
|
|
14773
14799
|
function startWizPoll() { stopWizPoll(); pollWizSetup(); wizPoll = setInterval(pollWizSetup, 5000); }
|
|
14774
14800
|
function pollWizSetup() {
|
|
14775
14801
|
if (!wizBotId) return;
|
|
14802
|
+
// \u65B0 bot \u9ED8\u8BA4\u5C31\u52A0\u5165\u6D3B\u8DC3\u96C6\u2014\u2014\u7528\u6237\u4E0D\u5FC5\u624B\u52A8\u70B9\u6309\u94AE / \u8DD1 bot use\u3002\u4E00\u6B21\u6027\uFF1B\u5931\u8D25\u4E0B\u5468\u671F\u91CD\u8BD5\u3002
|
|
14803
|
+
// \u771F\u6B63\u300C\u62C9\u8D77\u4E0A\u7EBF\u300D\u8981\u91CD\u542F Feishu Bridge\uFF0C\u90A3\u4E00\u6B65\u7559\u5230\u300C\u5B8C\u6210\u300D\u65F6\u5F39\u7A97\u786E\u8BA4\uFF08\u91CD\u542F\u4F1A\u77ED\u6682
|
|
14804
|
+
// \u5F71\u54CD\u5176\u5B83\u5728\u7EBF bot\uFF0C\u6240\u4EE5\u4E0D\u9759\u9ED8\u91CD\u542F\uFF09\u3002
|
|
14805
|
+
if (!wizAutoEnabled) {
|
|
14806
|
+
wizAutoEnabled = true;
|
|
14807
|
+
fetch('/api/bots/' + encodeURIComponent(wizBotId), {
|
|
14808
|
+
method: 'PATCH', headers: { 'Content-Type': 'application/json' },
|
|
14809
|
+
body: JSON.stringify({ enabled: true }),
|
|
14810
|
+
}).catch(function () { wizAutoEnabled = false; });
|
|
14811
|
+
}
|
|
14776
14812
|
fetch('/api/bots/' + encodeURIComponent(wizBotId) + '/setup-status')
|
|
14777
14813
|
.then(function (r) { return r.json(); })
|
|
14778
14814
|
.then(function (s) {
|
|
14779
14815
|
wizSetup = s;
|
|
14780
14816
|
if (wizStep === 2) renderWizChecklist();
|
|
14781
|
-
if (s.event && s.event.state === 'ok') stopWizPoll();
|
|
14782
14817
|
})
|
|
14783
14818
|
.catch(function () { /* \u4E0B\u4E2A\u5468\u671F\u91CD\u8BD5 */ });
|
|
14784
14819
|
}
|
|
@@ -14805,7 +14840,7 @@ ${UI_PURE_JS}
|
|
|
14805
14840
|
var s = wizSetup;
|
|
14806
14841
|
if (!s || !s.credentials) {
|
|
14807
14842
|
w.appendChild(checkItem('spin', '\u6B63\u5728\u68C0\u6D4B\u2026', '\u9996\u6B21\u62C9\u53D6\u7EA6 2~3 \u79D2'));
|
|
14808
|
-
w.appendChild(wizChecklistActions(
|
|
14843
|
+
w.appendChild(wizChecklistActions());
|
|
14809
14844
|
return;
|
|
14810
14845
|
}
|
|
14811
14846
|
w.appendChild(checkItem(
|
|
@@ -14833,81 +14868,58 @@ ${UI_PURE_JS}
|
|
|
14833
14868
|
} else if (conn.running) {
|
|
14834
14869
|
w.appendChild(checkItem('spin', 'bridge \u8FD0\u884C\u4E2D', '\u957F\u8FDE\u63A5' + (conn.connection ? '\uFF08' + conn.connection + '\uFF09' : '\u5EFA\u7ACB\u4E2D\u2026')));
|
|
14835
14870
|
} else {
|
|
14836
|
-
|
|
14837
|
-
|
|
14838
|
-
|
|
14839
|
-
|
|
14840
|
-
|
|
14841
|
-
|
|
14842
|
-
|
|
14843
|
-
|
|
14844
|
-
|
|
14845
|
-
|
|
14846
|
-
|
|
14847
|
-
|
|
14848
|
-
|
|
14849
|
-
}
|
|
14850
|
-
var ev = s.event || { state: 'unchecked' };
|
|
14851
|
-
if (ev.state === 'ok') {
|
|
14852
|
-
w.appendChild(checkItem('\u2705', '\u4E8B\u4EF6\u8BA2\u9605\u5DF2\u751F\u6548', eventDiagText(ev)));
|
|
14853
|
-
} else {
|
|
14854
|
-
var evExtra = el('div');
|
|
14855
|
-
evExtra.appendChild(el('div', 'note', ev.state === 'unchecked'
|
|
14856
|
-
? '\uFF08\u7F3A application:app_version \u53EA\u8BFB scope \u6216\u7F51\u7EDC\u4E0D\u901A\u65F6\u65E0\u6CD5\u81EA\u52A8\u68C0\u6D4B\uFF1B\u6309\u4E0B\u65B9\u6DF1\u94FE\u624B\u52A8\u6838\u5BF9\u300C\u4E8B\u4EF6\u914D\u7F6E\u300D\u3002\uFF09'
|
|
14857
|
-
: '\u53BB\u5F00\u53D1\u8005\u540E\u53F0\u300C\u4E8B\u4EF6\u4E0E\u56DE\u8C03\u300D\uFF1A\u4E8B\u4EF6\u914D\u7F6E\u6539\u300C\u957F\u8FDE\u63A5\u300D\u2192 \u6DFB\u52A0 im.message.receive_v1 \u2192 \u5E94\u7528\u53D1\u5E03\u91CC\u521B\u5EFA\u5E76\u53D1\u5E03\u7248\u672C\u3002'));
|
|
14858
|
-
var ea = el('a', null, '\u6253\u5F00\u300C\u4E8B\u4EF6\u4E0E\u56DE\u8C03\u300D\u914D\u7F6E\u9875 \u2197');
|
|
14859
|
-
ea.href = s.eventConfigUrl; ea.target = '_blank'; ea.rel = 'noopener';
|
|
14860
|
-
evExtra.appendChild(ea);
|
|
14861
|
-
evExtra.appendChild(el('div', 'note', '\u914D\u7F6E\u597D\u540E\u65E0\u9700\u624B\u52A8\u5237\u65B0\u2014\u2014\u672C\u9875\u6BCF 5 \u79D2\u81EA\u52A8\u590D\u68C0\uFF0C\u751F\u6548\u4F1A\u53D8 \u2705\u3002'));
|
|
14862
|
-
w.appendChild(checkItem(ev.state === 'unchecked' ? '\u26A0\uFE0F' : 'spin',
|
|
14863
|
-
ev.state === 'unchecked' ? '\u4E8B\u4EF6\u8BA2\u9605\u672A\u80FD\u81EA\u52A8\u68C0\u6D4B' : '\u4E8B\u4EF6\u8BA2\u9605\u5C1A\u672A\u751F\u6548',
|
|
14864
|
-
eventDiagText(ev), evExtra));
|
|
14865
|
-
}
|
|
14866
|
-
w.appendChild(wizChecklistActions(ev.state === 'ok'));
|
|
14871
|
+
// \u65B0 bot \u5DF2\u81EA\u52A8\u52A0\u5165\u6D3B\u8DC3\u96C6\uFF08\u89C1 pollWizSetup\uFF09\uFF1B\u4E0D\u518D\u8BA9\u7528\u6237\u70B9\u6309\u94AE / \u590D\u5236\u547D\u4EE4\u3002\u771F\u6B63\u62C9\u8D77
|
|
14872
|
+
// \u4E0A\u7EBF\u9760\u6700\u540E\u4E00\u6B65\u300C\u5B8C\u6210\u300D\u65F6\u5F39\u7A97\u786E\u8BA4\u91CD\u542F Feishu Bridge\u3002
|
|
14873
|
+
w.appendChild(checkItem('spin', '\u5F85\u62C9\u8D77\u4E0A\u7EBF', '\u5DF2\u81EA\u52A8\u52A0\u5165\u6D3B\u8DC3\u96C6 \xB7 \u70B9\u300C\u4E0B\u4E00\u6B65\u300D\u5230\u5B8C\u6210\u9875\uFF0C\u786E\u8BA4\u91CD\u542F Feishu Bridge \u5373\u4E0A\u7EBF\u3002'));
|
|
14874
|
+
}
|
|
14875
|
+
// \u4E8B\u4EF6\u8BA2\u9605\uFF1A\u7CFB\u7EDF\u65E0\u6CD5\u53EF\u9760\u68C0\u6D4B\uFF08\u957F\u8FDE\u63A5\u8BA2\u9605\u5728\u5DF2\u53D1\u5E03\u7248\u672C\u91CC\u7684\u4F53\u73B0\u4E0D\u7A33\u5B9A\uFF09\uFF0C\u6545\u53EA\u505A\u63D0\u9192\u3001\u4E0D\u4E0B\u7ED3\u8BBA\u3001
|
|
14876
|
+
// \u4E0D\u963B\u585E\u300C\u4E0B\u4E00\u6B65\u300D\u3002\u7528\u6237\u81EA\u884C\u53BB\u540E\u53F0\u6838\u5BF9\u3002
|
|
14877
|
+
var evHint = el('div');
|
|
14878
|
+
var ea = el('a', null, '\u6253\u5F00\u300C\u4E8B\u4EF6\u4E0E\u56DE\u8C03\u300D\u914D\u7F6E\u9875 \u2197');
|
|
14879
|
+
ea.href = (s.eventConfigUrl || '#'); ea.target = '_blank'; ea.rel = 'noopener';
|
|
14880
|
+
evHint.appendChild(ea);
|
|
14881
|
+
w.appendChild(checkItem('\u2139\uFE0F', '\u4E8B\u4EF6\u8BA2\u9605\uFF08\u8BF7\u81EA\u884C\u786E\u8BA4\uFF09',
|
|
14882
|
+
'\u8BF7\u5230\u300C\u4E8B\u4EF6\u4E0E\u56DE\u8C03\u300D\u786E\u8BA4\u5DF2\u8BA2\u9605 im.message.receive_v1\uFF08\u957F\u8FDE\u63A5\u6A21\u5F0F\uFF09\u5E76\u5DF2\u53D1\u5E03\u7248\u672C\uFF0C\u5426\u5219 @\u673A\u5668\u4EBA\u4E0D\u4F1A\u6709\u53CD\u5E94\u3002\u6B64\u9879\u7CFB\u7EDF\u65E0\u6CD5\u53EF\u9760\u68C0\u6D4B\uFF0C\u4EC5\u4F5C\u63D0\u9192\u3002', evHint));
|
|
14883
|
+
w.appendChild(wizChecklistActions());
|
|
14867
14884
|
}
|
|
14868
14885
|
|
|
14869
|
-
function wizChecklistActions(
|
|
14886
|
+
function wizChecklistActions() {
|
|
14870
14887
|
var actions = el('div', 'actions');
|
|
14871
14888
|
var back = el('button', 'btn', '\u7A0D\u540E\u518D\u8BF4');
|
|
14872
14889
|
back.onclick = closeWizard;
|
|
14873
14890
|
actions.appendChild(back);
|
|
14874
14891
|
actions.appendChild(el('div', 'grow'));
|
|
14875
|
-
var next = el('button', 'btn
|
|
14876
|
-
|
|
14877
|
-
else { next.className = 'btn disabled'; next.disabled = true; }
|
|
14892
|
+
var next = el('button', 'btn primary', '\u4E0B\u4E00\u6B65');
|
|
14893
|
+
next.onclick = function () { wizStep = 3; stopWizPoll(); renderWizard(); };
|
|
14878
14894
|
actions.appendChild(next);
|
|
14879
14895
|
return actions;
|
|
14880
14896
|
}
|
|
14881
14897
|
|
|
14882
|
-
// \
|
|
14883
|
-
// \
|
|
14884
|
-
function
|
|
14885
|
-
if (
|
|
14886
|
-
var
|
|
14887
|
-
|
|
14888
|
-
|
|
14889
|
-
|
|
14890
|
-
|
|
14891
|
-
|
|
14892
|
-
|
|
14893
|
-
|
|
14894
|
-
|
|
14895
|
-
|
|
14896
|
-
|
|
14897
|
-
|
|
14898
|
-
|
|
14899
|
-
|
|
14900
|
-
|
|
14901
|
-
|
|
14902
|
-
|
|
14903
|
-
|
|
14904
|
-
|
|
14905
|
-
|
|
14906
|
-
|
|
14907
|
-
postAction('/api/daemon/start', '\u542F\u52A8');
|
|
14908
|
-
}
|
|
14909
|
-
})
|
|
14910
|
-
.catch(function () { toast('\u274C \u8BF7\u6C42\u5931\u8D25'); });
|
|
14898
|
+
// \u5B8C\u6210\u6B65\uFF1A\u65B0 bot \u5DF2\u81EA\u52A8\u52A0\u5165\u6D3B\u8DC3\u96C6\uFF0C\u4F46\u8981\u91CD\u542F Feishu Bridge \u624D\u771F\u6B63\u62C9\u8D77\u4E0A\u7EBF\u3002\u5F39\u7A97\u786E\u8BA4
|
|
14899
|
+
// \uFF08\u91CD\u542F\u4F1A\u77ED\u6682\u5F71\u54CD\u5176\u5B83\u5728\u7EBF bot\uFF0C\u6240\u4EE5\u4E0D\u9759\u9ED8\u91CD\u542F\uFF09\uFF1Bdaemon \u6CA1\u5728\u8DD1\u5C31\u6539\u4E3A\u300C\u542F\u52A8\u300D\u3002\u4E00\u6B21\u6027\u3002
|
|
14900
|
+
function maybePromptRestartAtDone() {
|
|
14901
|
+
if (wizRestartPrompted) return;
|
|
14902
|
+
var conn = (wizSetup && wizSetup.connection) || {};
|
|
14903
|
+
if (conn.running && conn.connection === 'connected') return; // \u5DF2\u7ECF\u5728\u7EBF\uFF0C\u65E0\u9700\u91CD\u542F
|
|
14904
|
+
wizRestartPrompted = true;
|
|
14905
|
+
if (daemon && daemon.running) {
|
|
14906
|
+
confirmDialog({
|
|
14907
|
+
title: '\u{1F504} \u7ACB\u5373\u91CD\u542F Feishu Bridge \u8BA9\u65B0\u673A\u5668\u4EBA\u4E0A\u7EBF\uFF1F',
|
|
14908
|
+
lines: [
|
|
14909
|
+
'\u65B0\u673A\u5668\u4EBA\u5DF2\u52A0\u5165\u6D3B\u8DC3\u96C6\uFF0C\u91CD\u542F Feishu Bridge \u540E\u5373\u53EF\u4E0A\u7EBF\u3002',
|
|
14910
|
+
'\u91CD\u542F\u7EA6\u6570\u79D2\uFF0C\u671F\u95F4\u6240\u6709\u5728\u7EBF\u673A\u5668\u4EBA\u7684\u957F\u8FDE\u63A5\u4F1A\u77ED\u6682\u65AD\u5F00\u5E76\u81EA\u52A8\u91CD\u8FDE\u3002',
|
|
14911
|
+
],
|
|
14912
|
+
confirmLabel: '\u7ACB\u5373\u91CD\u542F',
|
|
14913
|
+
onConfirm: function () { postAction('/api/daemon/restart', '\u91CD\u542F'); },
|
|
14914
|
+
});
|
|
14915
|
+
} else {
|
|
14916
|
+
confirmDialog({
|
|
14917
|
+
title: '\u{1F680} \u7ACB\u5373\u542F\u52A8 Feishu Bridge \u8BA9\u673A\u5668\u4EBA\u4E0A\u7EBF\uFF1F',
|
|
14918
|
+
lines: ['Feishu Bridge \u5F53\u524D\u672A\u5728\u8FD0\u884C\uFF0C\u542F\u52A8\u540E\u65B0\u673A\u5668\u4EBA\u5373\u53EF\u4E0A\u7EBF\u3002'],
|
|
14919
|
+
confirmLabel: '\u7ACB\u5373\u542F\u52A8',
|
|
14920
|
+
onConfirm: function () { postAction('/api/daemon/start', '\u542F\u52A8'); },
|
|
14921
|
+
});
|
|
14922
|
+
}
|
|
14911
14923
|
}
|
|
14912
14924
|
|
|
14913
14925
|
function copyRow(text) {
|
|
@@ -14930,7 +14942,9 @@ ${UI_PURE_JS}
|
|
|
14930
14942
|
w.textContent = '';
|
|
14931
14943
|
w.appendChild(el('h3', null, '\u{1F389} \u63A5\u5165\u5B8C\u6210'));
|
|
14932
14944
|
w.appendChild(wizStepBar(3));
|
|
14933
|
-
w.appendChild(el('div', 'note', '\u673A\u5668\u4EBA\u300C' + ((wizSetup && wizSetup.botName) || wizBotId || '') + '\u300D\u5DF2\
|
|
14945
|
+
w.appendChild(el('div', 'note', '\u673A\u5668\u4EBA\u300C' + ((wizSetup && wizSetup.botName) || wizBotId || '') + '\u300D\u5DF2\u52A0\u5165\u6D3B\u8DC3\u96C6\u3002'));
|
|
14946
|
+
// \u8FDB\u5165\u5B8C\u6210\u9875\u5373\u5F39\u7A97\u786E\u8BA4\u91CD\u542F Feishu Bridge \u628A\u65B0 bot \u62C9\u8D77\u4E0A\u7EBF\uFF08\u4E00\u6B21\u6027\uFF1B\u5DF2\u5728\u7EBF\u5219\u4E0D\u5F39\uFF09\u3002
|
|
14947
|
+
maybePromptRestartAtDone();
|
|
14934
14948
|
var ul = el('div'); ul.style.margin = '12px 0';
|
|
14935
14949
|
[
|
|
14936
14950
|
'\u2460 \u5728\u98DE\u4E66\u91CC\u79C1\u804A\u8FD9\u4E2A\u673A\u5668\u4EBA\uFF0C\u70B9\u300C\u2795 \u65B0\u5EFA\u9879\u76EE\u300D\u628A\u4E00\u4E2A\u76EE\u5F55\u7ED1\u6210\u9879\u76EE\u7FA4\uFF1B',
|
|
@@ -15037,7 +15051,7 @@ var DEFAULT_WEB_PORT = 51847;
|
|
|
15037
15051
|
var COOKIE_NAME = "fcb_console_token";
|
|
15038
15052
|
var SSE_INITIAL_TAIL_BYTES = 16 * 1024;
|
|
15039
15053
|
function createWebServer(opts) {
|
|
15040
|
-
const token = opts.token ??
|
|
15054
|
+
const token = opts.token ?? randomUUID7();
|
|
15041
15055
|
const html = opts.html ?? UI_HTML;
|
|
15042
15056
|
const logDir = opts.logDir ?? join19(paths.appDir, "logs");
|
|
15043
15057
|
const sseCleanups = /* @__PURE__ */ new Set();
|
|
@@ -15380,7 +15394,7 @@ function createWebServer(opts) {
|
|
|
15380
15394
|
function handleRegisterQrStream(req, res) {
|
|
15381
15395
|
qrSession?.abort.abort();
|
|
15382
15396
|
const abort = new AbortController();
|
|
15383
|
-
const session = { id:
|
|
15397
|
+
const session = { id: randomUUID7(), abort };
|
|
15384
15398
|
qrSession = session;
|
|
15385
15399
|
res.writeHead(200, {
|
|
15386
15400
|
"Content-Type": "text/event-stream",
|
|
@@ -15657,23 +15671,27 @@ async function readJsonBody(req) {
|
|
|
15657
15671
|
}
|
|
15658
15672
|
|
|
15659
15673
|
// src/web/mount.ts
|
|
15674
|
+
async function listenCanonical(web, attempts = 25, gapMs = 200) {
|
|
15675
|
+
for (let i = 0; i < attempts; i++) {
|
|
15676
|
+
try {
|
|
15677
|
+
return await web.listen(DEFAULT_WEB_PORT);
|
|
15678
|
+
} catch (err) {
|
|
15679
|
+
if (err.code !== "EADDRINUSE") throw err;
|
|
15680
|
+
if (i < attempts - 1) await new Promise((r) => setTimeout(r, gapMs));
|
|
15681
|
+
}
|
|
15682
|
+
}
|
|
15683
|
+
log.warn("web", "console-port-busy-fallback", { preferred: DEFAULT_WEB_PORT });
|
|
15684
|
+
return web.listen(0);
|
|
15685
|
+
}
|
|
15660
15686
|
async function mountWebConsole(service) {
|
|
15661
|
-
const web = createWebServer({ service });
|
|
15687
|
+
const web = createWebServer({ service, token: stableWebConsoleToken() });
|
|
15662
15688
|
let port;
|
|
15663
15689
|
let url;
|
|
15664
15690
|
try {
|
|
15665
|
-
({ port, url } = await web
|
|
15691
|
+
({ port, url } = await listenCanonical(web));
|
|
15666
15692
|
} catch (err) {
|
|
15667
|
-
|
|
15668
|
-
|
|
15669
|
-
return void 0;
|
|
15670
|
-
}
|
|
15671
|
-
try {
|
|
15672
|
-
({ port, url } = await web.listen(0));
|
|
15673
|
-
} catch (err2) {
|
|
15674
|
-
log.fail("web", err2, { phase: "console-listen-fallback" });
|
|
15675
|
-
return void 0;
|
|
15676
|
-
}
|
|
15693
|
+
log.fail("web", err, { phase: "console-listen" });
|
|
15694
|
+
return void 0;
|
|
15677
15695
|
}
|
|
15678
15696
|
publishWebConsole({ port, token: web.token, pid: process.pid, startedAt: Date.now() });
|
|
15679
15697
|
const exitCleanup = () => clearWebConsole();
|
|
@@ -16469,14 +16487,14 @@ async function runWeb(opts = {}) {
|
|
|
16469
16487
|
console.log(" \xB7 \u4EC5\u672C\u673A\u53EF\u8BBF\u95EE\uFF08127.0.0.1\uFF09\uFF1BURL \u542B token\uFF0C\u8BF7\u52FF\u5916\u4F20/\u622A\u56FE\u3002");
|
|
16470
16488
|
return;
|
|
16471
16489
|
}
|
|
16472
|
-
const port = opts.port ??
|
|
16490
|
+
const port = opts.port ?? 0;
|
|
16473
16491
|
if (!Number.isInteger(port) || port < 0 || port > 65535) {
|
|
16474
16492
|
console.error(`\u2717 \u65E0\u6548\u7AEF\u53E3\uFF1A${opts.port}`);
|
|
16475
16493
|
process.exitCode = 1;
|
|
16476
16494
|
return;
|
|
16477
16495
|
}
|
|
16478
16496
|
const service = createReadonlyAdminService({ startDaemon: () => spawnDaemonControl("start") });
|
|
16479
|
-
const web = createWebServer({ service, liveConsole: () => readWebConsole() });
|
|
16497
|
+
const web = createWebServer({ service, token: stableWebConsoleToken(), liveConsole: () => readWebConsole() });
|
|
16480
16498
|
let url;
|
|
16481
16499
|
try {
|
|
16482
16500
|
({ url } = await web.listen(port));
|
package/dist/index.d.ts
CHANGED
|
@@ -55,6 +55,9 @@ declare const paths: {
|
|
|
55
55
|
/** daemon 内嵌 Web 控制台的发现文件 {port, token, pid}(0600,daemon 退出
|
|
56
56
|
* 清理)——`web` 子命令据此直接打开 daemon 控制台而不是再起只读副本。 */
|
|
57
57
|
webConsoleFile: string;
|
|
58
|
+
/** 稳定的 Web 控制台 token(0600,**不随进程退出清理**)——让重启 / 预览→daemon
|
|
59
|
+
* 切换后浏览器里那条带 token 的 URL 始终有效,不再 401。删此文件即轮换 token。 */
|
|
60
|
+
webTokenFile: string;
|
|
58
61
|
};
|
|
59
62
|
|
|
60
63
|
export { log, newTraceId, paths, withTrace };
|
package/dist/index.js
CHANGED
|
@@ -61,7 +61,10 @@ var paths = {
|
|
|
61
61
|
inboundDir: join(appDir, "inbound"),
|
|
62
62
|
/** daemon 内嵌 Web 控制台的发现文件 {port, token, pid}(0600,daemon 退出
|
|
63
63
|
* 清理)——`web` 子命令据此直接打开 daemon 控制台而不是再起只读副本。 */
|
|
64
|
-
webConsoleFile: join(appDir, "web-console.json")
|
|
64
|
+
webConsoleFile: join(appDir, "web-console.json"),
|
|
65
|
+
/** 稳定的 Web 控制台 token(0600,**不随进程退出清理**)——让重启 / 预览→daemon
|
|
66
|
+
* 切换后浏览器里那条带 token 的 URL 始终有效,不再 401。删此文件即轮换 token。 */
|
|
67
|
+
webTokenFile: join(appDir, "web-token")
|
|
65
68
|
};
|
|
66
69
|
|
|
67
70
|
// src/core/logger.ts
|
package/package.json
CHANGED