@modelzen/feishu-codex-bridge 0.4.0 → 0.4.2
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 +163 -95
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2950,7 +2950,14 @@ function card(elements, opts = {}) {
|
|
|
2950
2950
|
obj.header = {
|
|
2951
2951
|
template: opts.header.template ?? "blue",
|
|
2952
2952
|
title: { tag: "plain_text", content: opts.header.title },
|
|
2953
|
-
...opts.header.subtitle ? { subtitle: { tag: "plain_text", content: opts.header.subtitle } } : {}
|
|
2953
|
+
...opts.header.subtitle ? { subtitle: { tag: "plain_text", content: opts.header.subtitle } } : {},
|
|
2954
|
+
...opts.header.textTags?.length ? {
|
|
2955
|
+
text_tag_list: opts.header.textTags.map((t) => ({
|
|
2956
|
+
tag: "text_tag",
|
|
2957
|
+
text: { tag: "plain_text", content: t.text },
|
|
2958
|
+
color: t.color
|
|
2959
|
+
}))
|
|
2960
|
+
} : {}
|
|
2954
2961
|
};
|
|
2955
2962
|
}
|
|
2956
2963
|
return obj;
|
|
@@ -3025,6 +3032,27 @@ function actions(items, elementId) {
|
|
|
3025
3032
|
columns: items.map((it) => ({ tag: "column", width: "auto", elements: [it] }))
|
|
3026
3033
|
};
|
|
3027
3034
|
}
|
|
3035
|
+
function actionsFixed(items, width, elementId) {
|
|
3036
|
+
return {
|
|
3037
|
+
tag: "column_set",
|
|
3038
|
+
...elementId ? { element_id: elementId } : {},
|
|
3039
|
+
flex_mode: "flow",
|
|
3040
|
+
horizontal_spacing: "8px",
|
|
3041
|
+
columns: items.map((it) => ({ tag: "column", width: "auto", elements: [{ ...it, width, size: "large" }] }))
|
|
3042
|
+
};
|
|
3043
|
+
}
|
|
3044
|
+
function splitRow(left, right, elementId) {
|
|
3045
|
+
return {
|
|
3046
|
+
tag: "column_set",
|
|
3047
|
+
...elementId ? { element_id: elementId } : {},
|
|
3048
|
+
flex_mode: "none",
|
|
3049
|
+
horizontal_spacing: "medium",
|
|
3050
|
+
columns: [
|
|
3051
|
+
{ tag: "column", width: "auto", vertical_align: "center", elements: [left] },
|
|
3052
|
+
{ tag: "column", width: "weighted", weight: 1, vertical_align: "center", elements: [right] }
|
|
3053
|
+
]
|
|
3054
|
+
};
|
|
3055
|
+
}
|
|
3028
3056
|
function button(label, value, type = "default") {
|
|
3029
3057
|
return {
|
|
3030
3058
|
tag: "button",
|
|
@@ -3033,11 +3061,12 @@ function button(label, value, type = "default") {
|
|
|
3033
3061
|
behaviors: [{ type: "callback", value }]
|
|
3034
3062
|
};
|
|
3035
3063
|
}
|
|
3036
|
-
function linkButton(label, url, type = "default") {
|
|
3064
|
+
function linkButton(label, url, type = "default", size) {
|
|
3037
3065
|
return {
|
|
3038
3066
|
tag: "button",
|
|
3039
3067
|
text: { tag: "plain_text", content: label },
|
|
3040
3068
|
type,
|
|
3069
|
+
...size ? { size } : {},
|
|
3041
3070
|
behaviors: [{ type: "open_url", default_url: url }]
|
|
3042
3071
|
};
|
|
3043
3072
|
}
|
|
@@ -3295,6 +3324,8 @@ function openChatUrl(chatId) {
|
|
|
3295
3324
|
return `https://applink.feishu.cn/client/chat/open?openChatId=${encodeURIComponent(chatId)}`;
|
|
3296
3325
|
}
|
|
3297
3326
|
var REPO = "https://github.com/modelzen/feishu-codex-bridge";
|
|
3327
|
+
var MENU_BTN_W_TOP = "152px";
|
|
3328
|
+
var MENU_BTN_W_BOT = "112px";
|
|
3298
3329
|
var DM = {
|
|
3299
3330
|
menu: "dm.menu",
|
|
3300
3331
|
newProject: "dm.newProject",
|
|
@@ -3351,24 +3382,47 @@ var GS = {
|
|
|
3351
3382
|
function kindLabel(kind) {
|
|
3352
3383
|
return kind === "single" ? "\u{1F4AC} \u5355\u4F1A\u8BDD\u7FA4" : "\u{1F465} \u591A\u8BDD\u9898\u7FA4";
|
|
3353
3384
|
}
|
|
3354
|
-
function buildDmMenuCard() {
|
|
3385
|
+
function buildDmMenuCard(opts = {}) {
|
|
3386
|
+
const { webConsoleUrl: webConsoleUrl2, version } = opts;
|
|
3355
3387
|
return card(
|
|
3356
3388
|
[
|
|
3357
3389
|
md("\u79C1\u804A\u7528\u4E8E**\u5EFA\u9879\u76EE\u548C\u7BA1\u7406**\uFF1B\u5177\u4F53\u4EFB\u52A1\u8BF7\u5230\u9879\u76EE\u7FA4\u91CC @\u6211\u3002"),
|
|
3358
3390
|
hr(),
|
|
3359
|
-
|
|
3391
|
+
// 两行按钮固定宽度、左对齐;两行宽度配平后总长相等、右边缘对齐(见 MENU_BTN_W_*)。
|
|
3392
|
+
actionsFixed([
|
|
3360
3393
|
button("\u2795 \u65B0\u5EFA\u9879\u76EE", { a: DM.newProject }, "primary"),
|
|
3361
3394
|
button("\u{1F4C1} \u9879\u76EE\u5217\u8868", { a: DM.projects }),
|
|
3362
3395
|
button("\u2699\uFE0F \u8BBE\u7F6E", { a: DM.settings })
|
|
3363
|
-
]),
|
|
3364
|
-
|
|
3396
|
+
], MENU_BTN_W_TOP),
|
|
3397
|
+
actionsFixed([
|
|
3365
3398
|
button("\u{1F4CA} \u7528\u91CF", { a: DM.usage }),
|
|
3366
3399
|
button("\u{1FA7A} \u8BCA\u65AD", { a: DM.doctor }),
|
|
3367
3400
|
button("\u{1F504} \u91CD\u8FDE", { a: DM.reconnect }),
|
|
3368
|
-
button("\u2B06\uFE0F \
|
|
3369
|
-
])
|
|
3401
|
+
button("\u2B06\uFE0F \u66F4\u65B0", { a: DM.update })
|
|
3402
|
+
], MENU_BTN_W_BOT),
|
|
3403
|
+
// 🌐 网页控制台:刻意低调——小号按钮靠左 + 右侧灰字说明;仅在 daemon 本机控制台
|
|
3404
|
+
// 在跑(webConsoleUrl 有值)时出现。按钮直接开 127.0.0.1 控制台——只有运行 bridge
|
|
3405
|
+
// 的这台机器打得开;其它电脑/手机点了会打不开(本机回环地址,飞书也分不出点击设备
|
|
3406
|
+
// 是不是本机),右侧文字已说明,按用户决定不另做处理。
|
|
3407
|
+
...webConsoleUrl2 ? [
|
|
3408
|
+
hr(),
|
|
3409
|
+
splitRow(
|
|
3410
|
+
linkButton("\u{1F310} \u7F51\u9875\u63A7\u5236\u53F0", webConsoleUrl2, "default", "small"),
|
|
3411
|
+
note("\u4EC5\u5728**\u8FD0\u884C bridge \u7684\u8FD9\u53F0\u7535\u8111**\u4E0A\u80FD\u6253\u5F00\uFF08\u672C\u673A\u5730\u5740\uFF09\u3002")
|
|
3412
|
+
)
|
|
3413
|
+
] : []
|
|
3370
3414
|
],
|
|
3371
|
-
{
|
|
3415
|
+
{
|
|
3416
|
+
header: {
|
|
3417
|
+
title: "\u{1F916} Codex Bridge \u7BA1\u7406\u53F0",
|
|
3418
|
+
template: "blue",
|
|
3419
|
+
textTags: version ? [{ text: `v${version}`, color: "green" }] : void 0
|
|
3420
|
+
},
|
|
3421
|
+
// 这张卡可能内嵌带 token 的本机控制台直达链接(pc_url),且按钮全是管理员专属的
|
|
3422
|
+
// dm.* 回调——转发出去既无意义、又会把 token 链接一并带走。loopback 已使转发副本
|
|
3423
|
+
// 在他人设备上不可用,这里再加一道:禁止转发。
|
|
3424
|
+
forward: false
|
|
3425
|
+
}
|
|
3372
3426
|
);
|
|
3373
3427
|
}
|
|
3374
3428
|
var backToMenu = () => actions([button("\u2B05\uFE0F \u83DC\u5355", { a: DM.menu })]);
|
|
@@ -6751,6 +6805,71 @@ function buildUsageShareCard(data, opts = {}) {
|
|
|
6751
6805
|
});
|
|
6752
6806
|
}
|
|
6753
6807
|
|
|
6808
|
+
// src/web/discovery.ts
|
|
6809
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
6810
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync5, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
6811
|
+
import { dirname as dirname10 } from "path";
|
|
6812
|
+
function publishWebConsole(rec, file = paths.webConsoleFile) {
|
|
6813
|
+
mkdirSync2(dirname10(file), { recursive: true });
|
|
6814
|
+
try {
|
|
6815
|
+
unlinkSync(file);
|
|
6816
|
+
} catch {
|
|
6817
|
+
}
|
|
6818
|
+
writeFileSync2(file, `${JSON.stringify(rec, null, 2)}
|
|
6819
|
+
`, { mode: 384 });
|
|
6820
|
+
}
|
|
6821
|
+
function readWebConsole(file = paths.webConsoleFile) {
|
|
6822
|
+
try {
|
|
6823
|
+
const rec = JSON.parse(readFileSync5(file, "utf8"));
|
|
6824
|
+
if (typeof rec.port !== "number" || typeof rec.token !== "string" || rec.token === "" || typeof rec.pid !== "number") {
|
|
6825
|
+
return void 0;
|
|
6826
|
+
}
|
|
6827
|
+
if (!isAlive(rec.pid)) return void 0;
|
|
6828
|
+
return rec;
|
|
6829
|
+
} catch {
|
|
6830
|
+
return void 0;
|
|
6831
|
+
}
|
|
6832
|
+
}
|
|
6833
|
+
function webConsoleUrl(file = paths.webConsoleFile) {
|
|
6834
|
+
const rec = readWebConsole(file);
|
|
6835
|
+
if (!rec) return void 0;
|
|
6836
|
+
return `http://127.0.0.1:${rec.port}/?token=${encodeURIComponent(rec.token)}`;
|
|
6837
|
+
}
|
|
6838
|
+
function clearWebConsole(file = paths.webConsoleFile) {
|
|
6839
|
+
try {
|
|
6840
|
+
const rec = JSON.parse(readFileSync5(file, "utf8"));
|
|
6841
|
+
if (rec.pid === process.pid) unlinkSync(file);
|
|
6842
|
+
} catch {
|
|
6843
|
+
}
|
|
6844
|
+
}
|
|
6845
|
+
function stableWebConsoleToken(file = paths.webTokenFile) {
|
|
6846
|
+
try {
|
|
6847
|
+
const t = readFileSync5(file, "utf8").trim();
|
|
6848
|
+
if (t) return t;
|
|
6849
|
+
} catch {
|
|
6850
|
+
}
|
|
6851
|
+
const token = randomUUID3();
|
|
6852
|
+
try {
|
|
6853
|
+
mkdirSync2(dirname10(file), { recursive: true });
|
|
6854
|
+
try {
|
|
6855
|
+
unlinkSync(file);
|
|
6856
|
+
} catch {
|
|
6857
|
+
}
|
|
6858
|
+
writeFileSync2(file, `${token}
|
|
6859
|
+
`, { mode: 384 });
|
|
6860
|
+
} catch {
|
|
6861
|
+
}
|
|
6862
|
+
return token;
|
|
6863
|
+
}
|
|
6864
|
+
function isAlive(pid) {
|
|
6865
|
+
try {
|
|
6866
|
+
process.kill(pid, 0);
|
|
6867
|
+
return true;
|
|
6868
|
+
} catch (err) {
|
|
6869
|
+
return err.code === "EPERM";
|
|
6870
|
+
}
|
|
6871
|
+
}
|
|
6872
|
+
|
|
6754
6873
|
// src/project/lifecycle.ts
|
|
6755
6874
|
import { mkdir as mkdir10 } from "fs/promises";
|
|
6756
6875
|
import { existsSync as existsSync9 } from "fs";
|
|
@@ -7019,8 +7138,8 @@ async function leaveChat(channel, chatId) {
|
|
|
7019
7138
|
|
|
7020
7139
|
// src/bot/session-store.ts
|
|
7021
7140
|
import { mkdir as mkdir11, readFile as readFile10, rename as rename5, writeFile as writeFile9 } from "fs/promises";
|
|
7022
|
-
import { randomUUID as
|
|
7023
|
-
import { dirname as
|
|
7141
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
7142
|
+
import { dirname as dirname11 } from "path";
|
|
7024
7143
|
var FILE_VERSION3 = 2;
|
|
7025
7144
|
var LEGACY_V1_SESSION_FIELD = "codexThreadId";
|
|
7026
7145
|
function migrate(raw) {
|
|
@@ -7056,8 +7175,8 @@ function withLock2(fn) {
|
|
|
7056
7175
|
return run;
|
|
7057
7176
|
}
|
|
7058
7177
|
async function write2(sessions) {
|
|
7059
|
-
await mkdir11(
|
|
7060
|
-
const tmp = `${paths.sessionsFile}.tmp-${process.pid}-${
|
|
7178
|
+
await mkdir11(dirname11(paths.sessionsFile), { recursive: true });
|
|
7179
|
+
const tmp = `${paths.sessionsFile}.tmp-${process.pid}-${randomUUID4()}`;
|
|
7061
7180
|
const body = { version: FILE_VERSION3, sessions };
|
|
7062
7181
|
await writeFile9(tmp, `${JSON.stringify(body, null, 2)}
|
|
7063
7182
|
`, "utf8");
|
|
@@ -7101,7 +7220,7 @@ async function handleDmConsole(channel, cfg, msg) {
|
|
|
7101
7220
|
await channel.send(msg.chatId, { markdown: "\u26D4 \u4EC5\u7BA1\u7406\u5458\u53EF\u5728\u79C1\u804A\u91CC\u7BA1\u7406\u9879\u76EE\u3002" }, { replyTo: msg.messageId }).catch(() => void 0);
|
|
7102
7221
|
return;
|
|
7103
7222
|
}
|
|
7104
|
-
await sendManagedCard(channel, msg.chatId, buildDmMenuCard(), msg.messageId).catch(
|
|
7223
|
+
await sendManagedCard(channel, msg.chatId, buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() }), msg.messageId).catch(
|
|
7105
7224
|
(err) => log.fail("console", err, { cmd: "menu-send" })
|
|
7106
7225
|
);
|
|
7107
7226
|
});
|
|
@@ -7502,6 +7621,12 @@ function sanitizeContext(s, maxLen, oneLine2) {
|
|
|
7502
7621
|
out = out.trim();
|
|
7503
7622
|
return out.length > maxLen ? `${out.slice(0, maxLen)}\u2026` : out;
|
|
7504
7623
|
}
|
|
7624
|
+
function prependBlock(block, text) {
|
|
7625
|
+
const base = text.trim();
|
|
7626
|
+
return base ? `${block}
|
|
7627
|
+
|
|
7628
|
+
${base}` : block;
|
|
7629
|
+
}
|
|
7505
7630
|
function weaveQuote(text, quoted) {
|
|
7506
7631
|
if (!quoted) return text;
|
|
7507
7632
|
const who = sanitizeContext(quoted.senderName, 40, true) || "\u67D0\u4EBA";
|
|
@@ -7510,10 +7635,7 @@ function weaveQuote(text, quoted) {
|
|
|
7510
7635
|
const block = `[\u7528\u6237\u5F15\u7528\u4E86\u4E00\u6761\u6D88\u606F\uFF08\u6765\u81EA ${who}\uFF09\uFF1A
|
|
7511
7636
|
${body}
|
|
7512
7637
|
]`;
|
|
7513
|
-
|
|
7514
|
-
return base ? `${block}
|
|
7515
|
-
|
|
7516
|
-
${base}` : block;
|
|
7638
|
+
return prependBlock(block, text);
|
|
7517
7639
|
}
|
|
7518
7640
|
function weaveThreadHistory(text, msgs) {
|
|
7519
7641
|
if (msgs.length === 0) return text;
|
|
@@ -7526,10 +7648,15 @@ function weaveThreadHistory(text, msgs) {
|
|
|
7526
7648
|
const block = `[\u8BDD\u9898\u4E2D\u5728\u6B64\u4E4B\u524D\u5DF2\u6709\u7684\u6D88\u606F\uFF08\u6309\u65F6\u95F4\u5148\u540E\u6392\u5217\uFF0C\u4F9B\u4F60\u7406\u89E3\u4E0A\u4E0B\u6587\uFF09\uFF1A
|
|
7527
7649
|
${lines.join("\n")}
|
|
7528
7650
|
]`;
|
|
7529
|
-
|
|
7530
|
-
|
|
7531
|
-
|
|
7532
|
-
|
|
7651
|
+
return prependBlock(block, text);
|
|
7652
|
+
}
|
|
7653
|
+
var SENDER_NAME_MAX = 40;
|
|
7654
|
+
function weaveSender(text, sender) {
|
|
7655
|
+
const id = (sender.senderId ?? "").trim();
|
|
7656
|
+
if (!id) return text;
|
|
7657
|
+
const who = sanitizeContext(sender.senderName ?? "", SENDER_NAME_MAX, true) || "\u67D0\u7528\u6237";
|
|
7658
|
+
const block = `[\u672C\u6761\u6D88\u606F\u7684\u53D1\u4FE1\u4EBA\uFF1A${who}\uFF08open_id\uFF1A${id}\uFF09]`;
|
|
7659
|
+
return prependBlock(block, text);
|
|
7533
7660
|
}
|
|
7534
7661
|
|
|
7535
7662
|
// src/bot/comments.ts
|
|
@@ -8271,6 +8398,7 @@ function createOrchestrator(channel, cfg, fallbackCwd) {
|
|
|
8271
8398
|
const quoted = await fetchQuotedMessage(channel, msg.replyToMessageId);
|
|
8272
8399
|
body = weaveQuote(body, quoted);
|
|
8273
8400
|
}
|
|
8401
|
+
body = weaveSender(body, msg);
|
|
8274
8402
|
return body;
|
|
8275
8403
|
}
|
|
8276
8404
|
async function handleTurn(msg, text, sessionKey, flat, project, perm) {
|
|
@@ -8854,7 +8982,7 @@ function createOrchestrator(channel, cfg, fallbackCwd) {
|
|
|
8854
8982
|
patch(evt, buildSettingsCard(cfg));
|
|
8855
8983
|
}
|
|
8856
8984
|
const freshMenu = (evt) => {
|
|
8857
|
-
patch(evt, buildDmMenuCard());
|
|
8985
|
+
patch(evt, buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() }));
|
|
8858
8986
|
};
|
|
8859
8987
|
const runUsage = (evt, force) => {
|
|
8860
8988
|
if (!dmAdmin(evt.operator?.openId)) return;
|
|
@@ -9204,7 +9332,7 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
9204
9332
|
const name = typeof value.n === "string" ? value.n : "";
|
|
9205
9333
|
patch(evt, async () => {
|
|
9206
9334
|
const p = await getProjectByName(name);
|
|
9207
|
-
if (!p) return buildDmMenuCard();
|
|
9335
|
+
if (!p) return buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() });
|
|
9208
9336
|
return buildAllowlistCard(p, await namesWithOperator(evt, p.allowedUsers ?? []));
|
|
9209
9337
|
});
|
|
9210
9338
|
}).on(DM.addAllowedForm, ({ evt, value }) => {
|
|
@@ -9236,7 +9364,7 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
9236
9364
|
patch(evt, async () => {
|
|
9237
9365
|
await updateProject(name, (p) => ({ allowedUsers: (p.allowedUsers ?? []).filter((x) => x !== id) }));
|
|
9238
9366
|
const fresh = await getProjectByName(name);
|
|
9239
|
-
if (!fresh) return buildDmMenuCard();
|
|
9367
|
+
if (!fresh) return buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() });
|
|
9240
9368
|
return buildAllowlistCard(fresh, await namesWithOperator(evt, fresh.allowedUsers ?? []));
|
|
9241
9369
|
});
|
|
9242
9370
|
}).on(DM.projectSettings, ({ evt, value }) => {
|
|
@@ -9244,14 +9372,14 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
9244
9372
|
const name = typeof value.n === "string" ? value.n : "";
|
|
9245
9373
|
patch(evt, async () => {
|
|
9246
9374
|
const p = await getProjectByName(name);
|
|
9247
|
-
return p ? buildProjectSettingsCard(p, backendDisplayName(p.backend)) : buildDmMenuCard();
|
|
9375
|
+
return p ? buildProjectSettingsCard(p, backendDisplayName(p.backend)) : buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() });
|
|
9248
9376
|
});
|
|
9249
9377
|
}).on(DM.projectTopics, ({ evt, value }) => {
|
|
9250
9378
|
if (!dmAdmin(evt.operator?.openId)) return;
|
|
9251
9379
|
const name = typeof value.n === "string" ? value.n : "";
|
|
9252
9380
|
patch(evt, async () => {
|
|
9253
9381
|
const p = await getProjectByName(name);
|
|
9254
|
-
if (!p) return buildDmMenuCard();
|
|
9382
|
+
if (!p) return buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() });
|
|
9255
9383
|
const sessions2 = (await listSessions()).filter((s) => s.chatId === p.chatId);
|
|
9256
9384
|
return buildProjectTopicsCard(p, sessions2);
|
|
9257
9385
|
});
|
|
@@ -9261,7 +9389,7 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
9261
9389
|
const on = value.v === "on";
|
|
9262
9390
|
patch(evt, async () => {
|
|
9263
9391
|
const r = await performSetNoMention({ projectName: name, on });
|
|
9264
|
-
if (!r.ok) return buildDmMenuCard();
|
|
9392
|
+
if (!r.ok) return buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() });
|
|
9265
9393
|
return buildProjectSettingsCard(r.project, backendDisplayName(r.project.backend));
|
|
9266
9394
|
});
|
|
9267
9395
|
}).on(DM.setAutoCompactDm, ({ evt, value }) => {
|
|
@@ -9270,7 +9398,7 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
9270
9398
|
const on = value.v === "on";
|
|
9271
9399
|
patch(evt, async () => {
|
|
9272
9400
|
const r = await performSetAutoCompact({ projectName: name, on, evictLiveSessionsForChat });
|
|
9273
|
-
if (!r.ok) return buildDmMenuCard();
|
|
9401
|
+
if (!r.ok) return buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() });
|
|
9274
9402
|
log.info("console", "project-autocompact", { project: name, on });
|
|
9275
9403
|
return buildProjectSettingsCard(r.project, backendDisplayName(r.project.backend));
|
|
9276
9404
|
});
|
|
@@ -9279,7 +9407,7 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
9279
9407
|
const name = typeof value.n === "string" ? value.n : "";
|
|
9280
9408
|
patch(evt, async () => {
|
|
9281
9409
|
const p = await getProjectByName(name);
|
|
9282
|
-
return p ? buildPermissionCard(p) : buildDmMenuCard();
|
|
9410
|
+
return p ? buildPermissionCard(p) : buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() });
|
|
9283
9411
|
});
|
|
9284
9412
|
}).on(DM.permissionSubmit, ({ evt, value, formValue }) => {
|
|
9285
9413
|
if (!dmAdmin(evt.operator?.openId)) return;
|
|
@@ -10080,7 +10208,7 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
10080
10208
|
}).catch(() => void 0);
|
|
10081
10209
|
return;
|
|
10082
10210
|
}
|
|
10083
|
-
await sendManagedCard(channel, op, buildDmMenuCard(), void 0, false, "open_id").catch(
|
|
10211
|
+
await sendManagedCard(channel, op, buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() }), void 0, false, "open_id").catch(
|
|
10084
10212
|
(err) => log.fail("console", err, { cmd: "menu-card" })
|
|
10085
10213
|
);
|
|
10086
10214
|
};
|
|
@@ -10346,7 +10474,7 @@ function withOwnerAdmin(base, ownerOpenId) {
|
|
|
10346
10474
|
|
|
10347
10475
|
// src/admin/host.ts
|
|
10348
10476
|
import { readdir as readdir4, stat as stat4 } from "fs/promises";
|
|
10349
|
-
import { dirname as
|
|
10477
|
+
import { dirname as dirname12, join as join18, resolve as resolve7 } from "path";
|
|
10350
10478
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
10351
10479
|
import { arch, platform as platform2, release } from "os";
|
|
10352
10480
|
function toDaemonStatus(opts) {
|
|
@@ -10398,7 +10526,7 @@ async function collectHostDoctor(logsDir2 = join18(paths.appDir, "logs")) {
|
|
|
10398
10526
|
};
|
|
10399
10527
|
}
|
|
10400
10528
|
function resolveCliBinPath3() {
|
|
10401
|
-
const distDir =
|
|
10529
|
+
const distDir = dirname12(fileURLToPath5(import.meta.url));
|
|
10402
10530
|
return resolve7(distDir, "..", "bin", "feishu-codex-bridge.mjs");
|
|
10403
10531
|
}
|
|
10404
10532
|
function buildDaemonControlCommand(action, binPath = resolveCliBinPath3(), nodePath = process.execPath) {
|
|
@@ -10448,7 +10576,7 @@ function createAdminService(deps = {}) {
|
|
|
10448
10576
|
try {
|
|
10449
10577
|
const raw = await readFile11(botPaths(botId).processesFile, "utf8");
|
|
10450
10578
|
const rec = JSON.parse(raw);
|
|
10451
|
-
if (typeof rec.pid === "number" &&
|
|
10579
|
+
if (typeof rec.pid === "number" && isAlive2(rec.pid)) {
|
|
10452
10580
|
return { running: true, pid: rec.pid, startedAt: rec.startedAt };
|
|
10453
10581
|
}
|
|
10454
10582
|
} catch {
|
|
@@ -10844,7 +10972,7 @@ async function probeAllBackends() {
|
|
|
10844
10972
|
function createReadonlyAdminService(deps = {}) {
|
|
10845
10973
|
return createAdminService({ startDaemon: deps.startDaemon, applyUpdate: deps.applyUpdate, readonlyPreview: true });
|
|
10846
10974
|
}
|
|
10847
|
-
function
|
|
10975
|
+
function isAlive2(pid) {
|
|
10848
10976
|
try {
|
|
10849
10977
|
process.kill(pid, 0);
|
|
10850
10978
|
return true;
|
|
@@ -10853,66 +10981,6 @@ function isAlive(pid) {
|
|
|
10853
10981
|
}
|
|
10854
10982
|
}
|
|
10855
10983
|
|
|
10856
|
-
// src/web/discovery.ts
|
|
10857
|
-
import { randomUUID as randomUUID4 } from "crypto";
|
|
10858
|
-
import { mkdirSync as mkdirSync2, readFileSync as readFileSync5, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
10859
|
-
import { dirname as dirname12 } from "path";
|
|
10860
|
-
function publishWebConsole(rec, file = paths.webConsoleFile) {
|
|
10861
|
-
mkdirSync2(dirname12(file), { recursive: true });
|
|
10862
|
-
try {
|
|
10863
|
-
unlinkSync(file);
|
|
10864
|
-
} catch {
|
|
10865
|
-
}
|
|
10866
|
-
writeFileSync2(file, `${JSON.stringify(rec, null, 2)}
|
|
10867
|
-
`, { mode: 384 });
|
|
10868
|
-
}
|
|
10869
|
-
function readWebConsole(file = paths.webConsoleFile) {
|
|
10870
|
-
try {
|
|
10871
|
-
const rec = JSON.parse(readFileSync5(file, "utf8"));
|
|
10872
|
-
if (typeof rec.port !== "number" || typeof rec.token !== "string" || rec.token === "" || typeof rec.pid !== "number") {
|
|
10873
|
-
return void 0;
|
|
10874
|
-
}
|
|
10875
|
-
if (!isAlive2(rec.pid)) return void 0;
|
|
10876
|
-
return rec;
|
|
10877
|
-
} catch {
|
|
10878
|
-
return void 0;
|
|
10879
|
-
}
|
|
10880
|
-
}
|
|
10881
|
-
function clearWebConsole(file = paths.webConsoleFile) {
|
|
10882
|
-
try {
|
|
10883
|
-
const rec = JSON.parse(readFileSync5(file, "utf8"));
|
|
10884
|
-
if (rec.pid === process.pid) unlinkSync(file);
|
|
10885
|
-
} catch {
|
|
10886
|
-
}
|
|
10887
|
-
}
|
|
10888
|
-
function stableWebConsoleToken(file = paths.webTokenFile) {
|
|
10889
|
-
try {
|
|
10890
|
-
const t = readFileSync5(file, "utf8").trim();
|
|
10891
|
-
if (t) return t;
|
|
10892
|
-
} catch {
|
|
10893
|
-
}
|
|
10894
|
-
const token = randomUUID4();
|
|
10895
|
-
try {
|
|
10896
|
-
mkdirSync2(dirname12(file), { recursive: true });
|
|
10897
|
-
try {
|
|
10898
|
-
unlinkSync(file);
|
|
10899
|
-
} catch {
|
|
10900
|
-
}
|
|
10901
|
-
writeFileSync2(file, `${token}
|
|
10902
|
-
`, { mode: 384 });
|
|
10903
|
-
} catch {
|
|
10904
|
-
}
|
|
10905
|
-
return token;
|
|
10906
|
-
}
|
|
10907
|
-
function isAlive2(pid) {
|
|
10908
|
-
try {
|
|
10909
|
-
process.kill(pid, 0);
|
|
10910
|
-
return true;
|
|
10911
|
-
} catch (err) {
|
|
10912
|
-
return err.code === "EPERM";
|
|
10913
|
-
}
|
|
10914
|
-
}
|
|
10915
|
-
|
|
10916
10984
|
// src/cli/commands/daemon-control.ts
|
|
10917
10985
|
function spawnDaemonControl(action) {
|
|
10918
10986
|
const { command, args } = buildDaemonControlCommand(action);
|