@modelzen/feishu-codex-bridge 0.4.1 → 0.4.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/dist/cli.js +378 -161
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -127,6 +127,13 @@ function secretKeyForApp(appId) {
|
|
|
127
127
|
function getShowToolCalls(cfg) {
|
|
128
128
|
return cfg.preferences?.showToolCalls !== false;
|
|
129
129
|
}
|
|
130
|
+
function getModelDisplay(cfg) {
|
|
131
|
+
const v = cfg.preferences?.showModel;
|
|
132
|
+
if (v === "running" || v === "always" || v === "off") return v;
|
|
133
|
+
if (v === true) return "always";
|
|
134
|
+
if (v === false) return "off";
|
|
135
|
+
return "running";
|
|
136
|
+
}
|
|
130
137
|
function getMaxConcurrentRuns(cfg) {
|
|
131
138
|
const raw = cfg.preferences?.maxConcurrentRuns;
|
|
132
139
|
if (typeof raw !== "number" || !Number.isFinite(raw) || raw < 1) return 10;
|
|
@@ -2950,7 +2957,14 @@ function card(elements, opts = {}) {
|
|
|
2950
2957
|
obj.header = {
|
|
2951
2958
|
template: opts.header.template ?? "blue",
|
|
2952
2959
|
title: { tag: "plain_text", content: opts.header.title },
|
|
2953
|
-
...opts.header.subtitle ? { subtitle: { tag: "plain_text", content: opts.header.subtitle } } : {}
|
|
2960
|
+
...opts.header.subtitle ? { subtitle: { tag: "plain_text", content: opts.header.subtitle } } : {},
|
|
2961
|
+
...opts.header.textTags?.length ? {
|
|
2962
|
+
text_tag_list: opts.header.textTags.map((t) => ({
|
|
2963
|
+
tag: "text_tag",
|
|
2964
|
+
text: { tag: "plain_text", content: t.text },
|
|
2965
|
+
color: t.color
|
|
2966
|
+
}))
|
|
2967
|
+
} : {}
|
|
2954
2968
|
};
|
|
2955
2969
|
}
|
|
2956
2970
|
return obj;
|
|
@@ -3025,6 +3039,27 @@ function actions(items, elementId) {
|
|
|
3025
3039
|
columns: items.map((it) => ({ tag: "column", width: "auto", elements: [it] }))
|
|
3026
3040
|
};
|
|
3027
3041
|
}
|
|
3042
|
+
function actionsFixed(items, width, elementId) {
|
|
3043
|
+
return {
|
|
3044
|
+
tag: "column_set",
|
|
3045
|
+
...elementId ? { element_id: elementId } : {},
|
|
3046
|
+
flex_mode: "flow",
|
|
3047
|
+
horizontal_spacing: "8px",
|
|
3048
|
+
columns: items.map((it) => ({ tag: "column", width: "auto", elements: [{ ...it, width, size: "large" }] }))
|
|
3049
|
+
};
|
|
3050
|
+
}
|
|
3051
|
+
function splitRow(left, right, elementId) {
|
|
3052
|
+
return {
|
|
3053
|
+
tag: "column_set",
|
|
3054
|
+
...elementId ? { element_id: elementId } : {},
|
|
3055
|
+
flex_mode: "none",
|
|
3056
|
+
horizontal_spacing: "medium",
|
|
3057
|
+
columns: [
|
|
3058
|
+
{ tag: "column", width: "auto", vertical_align: "center", elements: [left] },
|
|
3059
|
+
{ tag: "column", width: "weighted", weight: 1, vertical_align: "center", elements: [right] }
|
|
3060
|
+
]
|
|
3061
|
+
};
|
|
3062
|
+
}
|
|
3028
3063
|
function button(label, value, type = "default") {
|
|
3029
3064
|
return {
|
|
3030
3065
|
tag: "button",
|
|
@@ -3033,11 +3068,12 @@ function button(label, value, type = "default") {
|
|
|
3033
3068
|
behaviors: [{ type: "callback", value }]
|
|
3034
3069
|
};
|
|
3035
3070
|
}
|
|
3036
|
-
function linkButton(label, url, type = "default") {
|
|
3071
|
+
function linkButton(label, url, type = "default", size) {
|
|
3037
3072
|
return {
|
|
3038
3073
|
tag: "button",
|
|
3039
3074
|
text: { tag: "plain_text", content: label },
|
|
3040
3075
|
type,
|
|
3076
|
+
...size ? { size } : {},
|
|
3041
3077
|
behaviors: [{ type: "open_url", default_url: url }]
|
|
3042
3078
|
};
|
|
3043
3079
|
}
|
|
@@ -3295,6 +3331,8 @@ function openChatUrl(chatId) {
|
|
|
3295
3331
|
return `https://applink.feishu.cn/client/chat/open?openChatId=${encodeURIComponent(chatId)}`;
|
|
3296
3332
|
}
|
|
3297
3333
|
var REPO = "https://github.com/modelzen/feishu-codex-bridge";
|
|
3334
|
+
var MENU_BTN_W_TOP = "152px";
|
|
3335
|
+
var MENU_BTN_W_BOT = "112px";
|
|
3298
3336
|
var DM = {
|
|
3299
3337
|
menu: "dm.menu",
|
|
3300
3338
|
newProject: "dm.newProject",
|
|
@@ -3316,6 +3354,7 @@ var DM = {
|
|
|
3316
3354
|
rmDo: "dm.rmDo",
|
|
3317
3355
|
rmCancel: "dm.rmCancel",
|
|
3318
3356
|
setTools: "dm.set.tools",
|
|
3357
|
+
setShowModel: "dm.set.showModel",
|
|
3319
3358
|
setWatchdog: "dm.set.watchdog",
|
|
3320
3359
|
// 假死超时「自定义…」:watchdogCustom 打开输入卡,watchdogCustomSubmit 保存任意秒数
|
|
3321
3360
|
watchdogCustom: "dm.set.watchdog.custom",
|
|
@@ -3351,24 +3390,47 @@ var GS = {
|
|
|
3351
3390
|
function kindLabel(kind) {
|
|
3352
3391
|
return kind === "single" ? "\u{1F4AC} \u5355\u4F1A\u8BDD\u7FA4" : "\u{1F465} \u591A\u8BDD\u9898\u7FA4";
|
|
3353
3392
|
}
|
|
3354
|
-
function buildDmMenuCard() {
|
|
3393
|
+
function buildDmMenuCard(opts = {}) {
|
|
3394
|
+
const { webConsoleUrl: webConsoleUrl2, version } = opts;
|
|
3355
3395
|
return card(
|
|
3356
3396
|
[
|
|
3357
3397
|
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
3398
|
hr(),
|
|
3359
|
-
|
|
3399
|
+
// 两行按钮固定宽度、左对齐;两行宽度配平后总长相等、右边缘对齐(见 MENU_BTN_W_*)。
|
|
3400
|
+
actionsFixed([
|
|
3360
3401
|
button("\u2795 \u65B0\u5EFA\u9879\u76EE", { a: DM.newProject }, "primary"),
|
|
3361
3402
|
button("\u{1F4C1} \u9879\u76EE\u5217\u8868", { a: DM.projects }),
|
|
3362
3403
|
button("\u2699\uFE0F \u8BBE\u7F6E", { a: DM.settings })
|
|
3363
|
-
]),
|
|
3364
|
-
|
|
3404
|
+
], MENU_BTN_W_TOP),
|
|
3405
|
+
actionsFixed([
|
|
3365
3406
|
button("\u{1F4CA} \u7528\u91CF", { a: DM.usage }),
|
|
3366
3407
|
button("\u{1FA7A} \u8BCA\u65AD", { a: DM.doctor }),
|
|
3367
3408
|
button("\u{1F504} \u91CD\u8FDE", { a: DM.reconnect }),
|
|
3368
|
-
button("\u2B06\uFE0F \
|
|
3369
|
-
])
|
|
3409
|
+
button("\u2B06\uFE0F \u66F4\u65B0", { a: DM.update })
|
|
3410
|
+
], MENU_BTN_W_BOT),
|
|
3411
|
+
// 🌐 网页控制台:刻意低调——小号按钮靠左 + 右侧灰字说明;仅在 daemon 本机控制台
|
|
3412
|
+
// 在跑(webConsoleUrl 有值)时出现。按钮直接开 127.0.0.1 控制台——只有运行 bridge
|
|
3413
|
+
// 的这台机器打得开;其它电脑/手机点了会打不开(本机回环地址,飞书也分不出点击设备
|
|
3414
|
+
// 是不是本机),右侧文字已说明,按用户决定不另做处理。
|
|
3415
|
+
...webConsoleUrl2 ? [
|
|
3416
|
+
hr(),
|
|
3417
|
+
splitRow(
|
|
3418
|
+
linkButton("\u{1F310} \u7F51\u9875\u63A7\u5236\u53F0", webConsoleUrl2, "default", "small"),
|
|
3419
|
+
note("\u4EC5\u5728**\u8FD0\u884C bridge \u7684\u8FD9\u53F0\u7535\u8111**\u4E0A\u80FD\u6253\u5F00\uFF08\u672C\u673A\u5730\u5740\uFF09\u3002")
|
|
3420
|
+
)
|
|
3421
|
+
] : []
|
|
3370
3422
|
],
|
|
3371
|
-
{
|
|
3423
|
+
{
|
|
3424
|
+
header: {
|
|
3425
|
+
title: "\u{1F916} Codex Bridge \u7BA1\u7406\u53F0",
|
|
3426
|
+
template: "blue",
|
|
3427
|
+
textTags: version ? [{ text: `v${version}`, color: "green" }] : void 0
|
|
3428
|
+
},
|
|
3429
|
+
// 这张卡可能内嵌带 token 的本机控制台直达链接(pc_url),且按钮全是管理员专属的
|
|
3430
|
+
// dm.* 回调——转发出去既无意义、又会把 token 链接一并带走。loopback 已使转发副本
|
|
3431
|
+
// 在他人设备上不可用,这里再加一道:禁止转发。
|
|
3432
|
+
forward: false
|
|
3433
|
+
}
|
|
3372
3434
|
);
|
|
3373
3435
|
}
|
|
3374
3436
|
var backToMenu = () => actions([button("\u2B05\uFE0F \u83DC\u5355", { a: DM.menu })]);
|
|
@@ -3449,6 +3511,17 @@ function buildUpdateCard(state) {
|
|
|
3449
3511
|
);
|
|
3450
3512
|
}
|
|
3451
3513
|
}
|
|
3514
|
+
function buildReconnectCard(conn) {
|
|
3515
|
+
const template = conn === "connected" ? "green" : "orange";
|
|
3516
|
+
return card(
|
|
3517
|
+
[
|
|
3518
|
+
md(`\u957F\u8FDE\u63A5\u72B6\u6001\uFF1A**${conn}**`),
|
|
3519
|
+
note("SDK \u4F1A\u81EA\u52A8\u91CD\u8FDE\uFF1B\u82E5\u957F\u671F\u65AD\u5F00\uFF0C\u8BF7\u5728\u7EC8\u7AEF\u91CD\u8DD1 `feishu-codex-bridge run`\uFF08\u524D\u53F0\uFF09\u6216 `feishu-codex-bridge restart`\uFF08\u540E\u53F0\u5B88\u62A4\uFF09\u3002"),
|
|
3520
|
+
backToMenu()
|
|
3521
|
+
],
|
|
3522
|
+
{ header: { title: "\u{1F504} \u957F\u8FDE\u63A5", template } }
|
|
3523
|
+
);
|
|
3524
|
+
}
|
|
3452
3525
|
function connLabel(state) {
|
|
3453
3526
|
switch (state) {
|
|
3454
3527
|
case "connected":
|
|
@@ -3755,38 +3828,78 @@ function optionRow(label, actionId, current, opts) {
|
|
|
3755
3828
|
actions(opts.map((o) => button(o.label, { a: actionId, v: o.value }, o.value === current ? "primary" : "default")))
|
|
3756
3829
|
];
|
|
3757
3830
|
}
|
|
3831
|
+
function settingSection(title) {
|
|
3832
|
+
return { tag: "markdown", content: `**${title}**`, text_size: "notation", text_color: "grey" };
|
|
3833
|
+
}
|
|
3834
|
+
function settingItem(name, desc, actionId, current, opts) {
|
|
3835
|
+
return [
|
|
3836
|
+
md(`**${name}**`),
|
|
3837
|
+
note(desc),
|
|
3838
|
+
actions(opts.map((o) => button(o.label, { a: actionId, v: o.value }, o.value === current ? "primary" : "default")))
|
|
3839
|
+
];
|
|
3840
|
+
}
|
|
3758
3841
|
function buildSettingsCard(cfg) {
|
|
3759
3842
|
const watchdogSec = cfg.preferences?.runIdleTimeoutSeconds ?? 120;
|
|
3760
3843
|
return card(
|
|
3761
3844
|
[
|
|
3762
|
-
|
|
3763
|
-
...
|
|
3764
|
-
{
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3845
|
+
settingSection("\u{1F4E4} \u8F93\u51FA\u5C55\u793A"),
|
|
3846
|
+
...settingItem(
|
|
3847
|
+
"\u{1F527} \u5DE5\u5177\u8C03\u7528",
|
|
3848
|
+
"\u8F93\u51FA\u65F6\u663E\u793A\u6267\u884C\u7684\u547D\u4EE4 / \u5DE5\u5177\u8C03\u7528\uFF1B\u5173\u6389\u53EA\u770B\u6700\u7EC8\u56DE\u7B54\u3002",
|
|
3849
|
+
DM.setTools,
|
|
3850
|
+
getShowToolCalls(cfg) ? "on" : "off",
|
|
3851
|
+
[
|
|
3852
|
+
{ label: "\u663E\u793A", value: "on" },
|
|
3853
|
+
{ label: "\u9690\u85CF", value: "off" }
|
|
3854
|
+
]
|
|
3855
|
+
),
|
|
3856
|
+
...settingItem(
|
|
3857
|
+
"\u{1F9E0} \u6A21\u578B\u663E\u793A",
|
|
3858
|
+
"\u6BCF\u6761\u56DE\u590D\u53F3\u4E0B\u89D2\u663E\u793A\u300C\u6A21\u578B \xB7 \u63A8\u7406\u5F3A\u5EA6\u300D\u3002\u4EC5\u8F93\u51FA\u65F6\uFF1D\u53EA\u5728\u751F\u6210\u4E2D\u663E\u793A\uFF1B\u59CB\u7EC8\uFF1D\u751F\u6210\u5B8C\u540E\u5361\u7247\u4E5F\u4FDD\u7559\u3002",
|
|
3859
|
+
DM.setShowModel,
|
|
3860
|
+
getModelDisplay(cfg),
|
|
3861
|
+
[
|
|
3862
|
+
{ label: "\u5173\u95ED", value: "off" },
|
|
3863
|
+
{ label: "\u4EC5\u8F93\u51FA\u65F6", value: "running" },
|
|
3864
|
+
{ label: "\u59CB\u7EC8", value: "always" }
|
|
3865
|
+
]
|
|
3866
|
+
),
|
|
3867
|
+
hr(),
|
|
3868
|
+
settingSection("\u23F1 \u8FD0\u884C\u63A7\u5236"),
|
|
3869
|
+
md(`**\u23F1 \u5047\u6B7B\u8D85\u65F6** \xB7 \u5F53\u524D **${watchdogSec === 0 ? "\u5173\u95ED" : `${watchdogSec} \u79D2`}**`),
|
|
3870
|
+
note("\u591A\u4E45\u6CA1\u6709\u4EFB\u4F55\u8F93\u51FA\u5C31\u81EA\u52A8\u7EC8\u6B62\u672C\u8F6E\uFF08\u9632\u5361\u6B7B\uFF09\u3002"),
|
|
3768
3871
|
actions([
|
|
3769
3872
|
...[0, 120, 300].map(
|
|
3770
3873
|
(v) => button(v === 0 ? "\u5173\u95ED" : `${v}\u79D2`, { a: DM.setWatchdog, v: String(v) }, v === watchdogSec ? "primary" : "default")
|
|
3771
3874
|
),
|
|
3772
3875
|
button("\u81EA\u5B9A\u4E49\u2026", { a: DM.watchdogCustom })
|
|
3773
3876
|
]),
|
|
3774
|
-
...
|
|
3775
|
-
{
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3877
|
+
...settingItem(
|
|
3878
|
+
"\u{1F4E5} \u8FD0\u884C\u4E2D\u6765\u65B0\u6D88\u606F",
|
|
3879
|
+
"\u6B63\u5728\u8DD1\u65F6\u4F60\u53C8\u53D1\u6D88\u606F\uFF1A\u5F15\u5BFC\uFF1D\u63D2\u8FDB\u5F53\u524D\u8F6E\u7EA0\u504F\uFF1B\u6392\u961F\uFF1D\u7B49\u8FD9\u8F6E\u8DD1\u5B8C\u518D\u5904\u7406\u3002",
|
|
3880
|
+
DM.setPending,
|
|
3881
|
+
getPendingPolicy(cfg),
|
|
3882
|
+
[
|
|
3883
|
+
{ label: "\u5F15\u5BFC", value: "steer" },
|
|
3884
|
+
{ label: "\u6392\u961F", value: "queue" }
|
|
3885
|
+
]
|
|
3886
|
+
),
|
|
3887
|
+
...settingItem(
|
|
3888
|
+
"\u26A1 \u5E76\u53D1\u4E0A\u9650",
|
|
3889
|
+
"\u6240\u6709\u7FA4 / \u8BDD\u9898\u5168\u5C40\u540C\u65F6\u6700\u591A\u8DD1\u51E0\u4E2A\uFF0C\u6EE1\u4E86\u6392\u961F\uFF08\u6392\u961F\u5361\u53EF \u23F9 \u53D6\u6D88\uFF09\u3002\u6539\u540E\u9700\u91CD\u542F\u751F\u6548\u3002",
|
|
3890
|
+
DM.setConcurrency,
|
|
3891
|
+
String(getMaxConcurrentRuns(cfg)),
|
|
3892
|
+
[
|
|
3893
|
+
{ label: "1", value: "1" },
|
|
3894
|
+
{ label: "5", value: "5" },
|
|
3895
|
+
{ label: "10", value: "10" },
|
|
3896
|
+
{ label: "20", value: "20" }
|
|
3897
|
+
]
|
|
3898
|
+
),
|
|
3786
3899
|
hr(),
|
|
3787
3900
|
actions([button("\u{1F46E} \u7BA1\u7406\u5458", { a: DM.admins }), button("\u2B05\uFE0F \u83DC\u5355", { a: DM.menu })])
|
|
3788
3901
|
],
|
|
3789
|
-
{ header: { title: "\u2699\uFE0F \u8BBE\u7F6E", template: "blue" } }
|
|
3902
|
+
{ header: { title: "\u2699\uFE0F \u5168\u5C40\u8BBE\u7F6E", template: "blue" } }
|
|
3790
3903
|
);
|
|
3791
3904
|
}
|
|
3792
3905
|
function buildWatchdogCustomCard(cfg) {
|
|
@@ -4850,24 +4963,6 @@ function buildRunCard(rc) {
|
|
|
4850
4963
|
}
|
|
4851
4964
|
function renderRunning(state, rc) {
|
|
4852
4965
|
const elements = [];
|
|
4853
|
-
if (rc.cardKey && rc.goalControls) {
|
|
4854
|
-
if (rc.goalEnding) {
|
|
4855
|
-
elements.push(actions([button("\u23F9 \u7EC8\u6B62", { a: RC.stop, m: rc.cardKey }, "danger")], CONTROLS_EID));
|
|
4856
|
-
elements.push(noteMd("_\u{1F3AF} \u76EE\u6807\u5DF2\u89E3\u9664\uFF0C\u672C\u8F6E\u8F93\u51FA\u5B8C\u6210\u540E\u505C\u6B62_"));
|
|
4857
|
-
} else {
|
|
4858
|
-
elements.push(
|
|
4859
|
-
actions(
|
|
4860
|
-
[
|
|
4861
|
-
button("\u23F9 \u7EC8\u6B62", { a: RC.stop, m: rc.cardKey }, "danger"),
|
|
4862
|
-
button("\u{1F3AF} \u7ED3\u675F\u76EE\u6807", { a: RC.endGoal, m: rc.cardKey }, "default")
|
|
4863
|
-
],
|
|
4864
|
-
CONTROLS_EID
|
|
4865
|
-
)
|
|
4866
|
-
);
|
|
4867
|
-
}
|
|
4868
|
-
} else if (rc.cardKey && !rc.hideStop) {
|
|
4869
|
-
elements.push(actions([button("\u23F9 \u7EC8\u6B62", { a: RC.stop, m: rc.cardKey }, "danger")], CONTROLS_EID));
|
|
4870
|
-
}
|
|
4871
4966
|
const reasoning = reasoningContent(state);
|
|
4872
4967
|
if (reasoning) elements.push(reasoningPanel(reasoning, state.reasoningActive));
|
|
4873
4968
|
const showTools = rc.showTools !== false;
|
|
@@ -4883,9 +4978,30 @@ function renderRunning(state, rc) {
|
|
|
4883
4978
|
if (tools.length > 0) elements.push(...renderToolGroup(tools, false));
|
|
4884
4979
|
const answer = textParts.join("\n\n");
|
|
4885
4980
|
if (answer) elements.push(mdStream(answer, ANSWER_EID));
|
|
4886
|
-
|
|
4981
|
+
const mEl = modelEl(rc);
|
|
4982
|
+
if (state.footer && mEl) elements.push(splitRow(footerStatus(state.footer), mEl));
|
|
4983
|
+
else if (state.footer) elements.push(footerStatus(state.footer));
|
|
4984
|
+
else if (mEl) elements.push(mEl);
|
|
4887
4985
|
const gauge = gaugeEl(state);
|
|
4888
4986
|
if (gauge) elements.push(gauge);
|
|
4987
|
+
if (rc.cardKey && rc.goalControls) {
|
|
4988
|
+
if (rc.goalEnding) {
|
|
4989
|
+
elements.push(noteMd("_\u{1F3AF} \u76EE\u6807\u5DF2\u89E3\u9664\uFF0C\u672C\u8F6E\u8F93\u51FA\u5B8C\u6210\u540E\u505C\u6B62_"));
|
|
4990
|
+
elements.push(actions([button("\u23F9 \u7EC8\u6B62", { a: RC.stop, m: rc.cardKey }, "danger")], CONTROLS_EID));
|
|
4991
|
+
} else {
|
|
4992
|
+
elements.push(
|
|
4993
|
+
actions(
|
|
4994
|
+
[
|
|
4995
|
+
button("\u23F9 \u7EC8\u6B62", { a: RC.stop, m: rc.cardKey }, "danger"),
|
|
4996
|
+
button("\u{1F3AF} \u7ED3\u675F\u76EE\u6807", { a: RC.endGoal, m: rc.cardKey }, "default")
|
|
4997
|
+
],
|
|
4998
|
+
CONTROLS_EID
|
|
4999
|
+
)
|
|
5000
|
+
);
|
|
5001
|
+
}
|
|
5002
|
+
} else if (rc.cardKey && !rc.hideStop) {
|
|
5003
|
+
elements.push(actions([button("\u23F9 \u7EC8\u6B62", { a: RC.stop, m: rc.cardKey }, "danger")], CONTROLS_EID));
|
|
5004
|
+
}
|
|
4889
5005
|
return elements;
|
|
4890
5006
|
}
|
|
4891
5007
|
function renderTerminal(state, rc) {
|
|
@@ -4923,6 +5039,8 @@ function renderTerminal(state, rc) {
|
|
|
4923
5039
|
}
|
|
4924
5040
|
const gauge = gaugeEl(state);
|
|
4925
5041
|
if (gauge) elements.push(gauge);
|
|
5042
|
+
const mEl = rc.modelOnTerminal ? modelEl(rc) : null;
|
|
5043
|
+
if (mEl) elements.push(mEl);
|
|
4926
5044
|
return elements;
|
|
4927
5045
|
}
|
|
4928
5046
|
function errorAdvice(msg) {
|
|
@@ -5044,9 +5162,35 @@ function collapsedToolSummary(tools, finalized) {
|
|
|
5044
5162
|
body: tools.map((t) => `- ${toolHeaderText(t)}`).join("\n")
|
|
5045
5163
|
});
|
|
5046
5164
|
}
|
|
5165
|
+
function footerStatusText(status) {
|
|
5166
|
+
return status === "thinking" ? "\u{1F9E0} \u6B63\u5728\u601D\u8003" : status === "tool_running" ? "\u{1F9F0} \u6B63\u5728\u8C03\u7528\u5DE5\u5177" : status === "retrying" ? "\u26A0\uFE0F \u77AC\u65AD\uFF0C\u81EA\u52A8\u91CD\u8BD5\u4E2D\u2026" : "\u270D\uFE0F \u6B63\u5728\u8F93\u51FA";
|
|
5167
|
+
}
|
|
5047
5168
|
function footerStatus(status) {
|
|
5048
|
-
|
|
5049
|
-
|
|
5169
|
+
return noteMd(footerStatusText(status));
|
|
5170
|
+
}
|
|
5171
|
+
var EFFORT_TIER = {
|
|
5172
|
+
none: { label: "\u65E0", color: "grey" },
|
|
5173
|
+
minimal: { label: "\u6781\u7B80", color: "grey" },
|
|
5174
|
+
low: { label: "\u4F4E", color: "yellow" },
|
|
5175
|
+
medium: { label: "\u4E2D", color: "green" },
|
|
5176
|
+
high: { label: "\u9AD8", color: "violet" },
|
|
5177
|
+
xhigh: { label: "\u6781\u9AD8", color: "purple" }
|
|
5178
|
+
};
|
|
5179
|
+
function modelEffortMd(model, effort) {
|
|
5180
|
+
if (!effort) return model;
|
|
5181
|
+
const t = EFFORT_TIER[effort];
|
|
5182
|
+
if (!t) return `${model} \xB7 ${effort}`;
|
|
5183
|
+
return `${model} \xB7 <font color='${t.color}'>${t.label}</font>`;
|
|
5184
|
+
}
|
|
5185
|
+
function modelEl(rc) {
|
|
5186
|
+
if (!rc.model) return null;
|
|
5187
|
+
return {
|
|
5188
|
+
tag: "markdown",
|
|
5189
|
+
content: modelEffortMd(rc.model, rc.effort),
|
|
5190
|
+
text_size: "notation",
|
|
5191
|
+
text_color: "grey",
|
|
5192
|
+
text_align: "right"
|
|
5193
|
+
};
|
|
5050
5194
|
}
|
|
5051
5195
|
function summaryText(state) {
|
|
5052
5196
|
if (state.terminal === "interrupted") return "\u5DF2\u4E2D\u65AD";
|
|
@@ -6751,6 +6895,71 @@ function buildUsageShareCard(data, opts = {}) {
|
|
|
6751
6895
|
});
|
|
6752
6896
|
}
|
|
6753
6897
|
|
|
6898
|
+
// src/web/discovery.ts
|
|
6899
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
6900
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync5, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
6901
|
+
import { dirname as dirname10 } from "path";
|
|
6902
|
+
function publishWebConsole(rec, file = paths.webConsoleFile) {
|
|
6903
|
+
mkdirSync2(dirname10(file), { recursive: true });
|
|
6904
|
+
try {
|
|
6905
|
+
unlinkSync(file);
|
|
6906
|
+
} catch {
|
|
6907
|
+
}
|
|
6908
|
+
writeFileSync2(file, `${JSON.stringify(rec, null, 2)}
|
|
6909
|
+
`, { mode: 384 });
|
|
6910
|
+
}
|
|
6911
|
+
function readWebConsole(file = paths.webConsoleFile) {
|
|
6912
|
+
try {
|
|
6913
|
+
const rec = JSON.parse(readFileSync5(file, "utf8"));
|
|
6914
|
+
if (typeof rec.port !== "number" || typeof rec.token !== "string" || rec.token === "" || typeof rec.pid !== "number") {
|
|
6915
|
+
return void 0;
|
|
6916
|
+
}
|
|
6917
|
+
if (!isAlive(rec.pid)) return void 0;
|
|
6918
|
+
return rec;
|
|
6919
|
+
} catch {
|
|
6920
|
+
return void 0;
|
|
6921
|
+
}
|
|
6922
|
+
}
|
|
6923
|
+
function webConsoleUrl(file = paths.webConsoleFile) {
|
|
6924
|
+
const rec = readWebConsole(file);
|
|
6925
|
+
if (!rec) return void 0;
|
|
6926
|
+
return `http://127.0.0.1:${rec.port}/?token=${encodeURIComponent(rec.token)}`;
|
|
6927
|
+
}
|
|
6928
|
+
function clearWebConsole(file = paths.webConsoleFile) {
|
|
6929
|
+
try {
|
|
6930
|
+
const rec = JSON.parse(readFileSync5(file, "utf8"));
|
|
6931
|
+
if (rec.pid === process.pid) unlinkSync(file);
|
|
6932
|
+
} catch {
|
|
6933
|
+
}
|
|
6934
|
+
}
|
|
6935
|
+
function stableWebConsoleToken(file = paths.webTokenFile) {
|
|
6936
|
+
try {
|
|
6937
|
+
const t = readFileSync5(file, "utf8").trim();
|
|
6938
|
+
if (t) return t;
|
|
6939
|
+
} catch {
|
|
6940
|
+
}
|
|
6941
|
+
const token = randomUUID3();
|
|
6942
|
+
try {
|
|
6943
|
+
mkdirSync2(dirname10(file), { recursive: true });
|
|
6944
|
+
try {
|
|
6945
|
+
unlinkSync(file);
|
|
6946
|
+
} catch {
|
|
6947
|
+
}
|
|
6948
|
+
writeFileSync2(file, `${token}
|
|
6949
|
+
`, { mode: 384 });
|
|
6950
|
+
} catch {
|
|
6951
|
+
}
|
|
6952
|
+
return token;
|
|
6953
|
+
}
|
|
6954
|
+
function isAlive(pid) {
|
|
6955
|
+
try {
|
|
6956
|
+
process.kill(pid, 0);
|
|
6957
|
+
return true;
|
|
6958
|
+
} catch (err) {
|
|
6959
|
+
return err.code === "EPERM";
|
|
6960
|
+
}
|
|
6961
|
+
}
|
|
6962
|
+
|
|
6754
6963
|
// src/project/lifecycle.ts
|
|
6755
6964
|
import { mkdir as mkdir10 } from "fs/promises";
|
|
6756
6965
|
import { existsSync as existsSync9 } from "fs";
|
|
@@ -7019,8 +7228,8 @@ async function leaveChat(channel, chatId) {
|
|
|
7019
7228
|
|
|
7020
7229
|
// src/bot/session-store.ts
|
|
7021
7230
|
import { mkdir as mkdir11, readFile as readFile10, rename as rename5, writeFile as writeFile9 } from "fs/promises";
|
|
7022
|
-
import { randomUUID as
|
|
7023
|
-
import { dirname as
|
|
7231
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
7232
|
+
import { dirname as dirname11 } from "path";
|
|
7024
7233
|
var FILE_VERSION3 = 2;
|
|
7025
7234
|
var LEGACY_V1_SESSION_FIELD = "codexThreadId";
|
|
7026
7235
|
function migrate(raw) {
|
|
@@ -7056,8 +7265,8 @@ function withLock2(fn) {
|
|
|
7056
7265
|
return run;
|
|
7057
7266
|
}
|
|
7058
7267
|
async function write2(sessions) {
|
|
7059
|
-
await mkdir11(
|
|
7060
|
-
const tmp = `${paths.sessionsFile}.tmp-${process.pid}-${
|
|
7268
|
+
await mkdir11(dirname11(paths.sessionsFile), { recursive: true });
|
|
7269
|
+
const tmp = `${paths.sessionsFile}.tmp-${process.pid}-${randomUUID4()}`;
|
|
7061
7270
|
const body = { version: FILE_VERSION3, sessions };
|
|
7062
7271
|
await writeFile9(tmp, `${JSON.stringify(body, null, 2)}
|
|
7063
7272
|
`, "utf8");
|
|
@@ -7101,7 +7310,7 @@ async function handleDmConsole(channel, cfg, msg) {
|
|
|
7101
7310
|
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
7311
|
return;
|
|
7103
7312
|
}
|
|
7104
|
-
await sendManagedCard(channel, msg.chatId, buildDmMenuCard(), msg.messageId).catch(
|
|
7313
|
+
await sendManagedCard(channel, msg.chatId, buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() }), msg.messageId).catch(
|
|
7105
7314
|
(err) => log.fail("console", err, { cmd: "menu-send" })
|
|
7106
7315
|
);
|
|
7107
7316
|
});
|
|
@@ -8863,7 +9072,7 @@ function createOrchestrator(channel, cfg, fallbackCwd) {
|
|
|
8863
9072
|
patch(evt, buildSettingsCard(cfg));
|
|
8864
9073
|
}
|
|
8865
9074
|
const freshMenu = (evt) => {
|
|
8866
|
-
patch(evt, buildDmMenuCard());
|
|
9075
|
+
patch(evt, buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() }));
|
|
8867
9076
|
};
|
|
8868
9077
|
const runUsage = (evt, force) => {
|
|
8869
9078
|
if (!dmAdmin(evt.operator?.openId)) return;
|
|
@@ -8915,6 +9124,35 @@ function createOrchestrator(channel, cfg, fallbackCwd) {
|
|
|
8915
9124
|
}
|
|
8916
9125
|
return buildProjectListCard(projects, byChat);
|
|
8917
9126
|
};
|
|
9127
|
+
const buildDoctorInfo = async () => {
|
|
9128
|
+
const codexProbe = await backend.doctor({ force: true });
|
|
9129
|
+
const app = cfg.accounts.app;
|
|
9130
|
+
const secret = await getSecret(secretKeyForApp(app.id)).catch(() => void 0);
|
|
9131
|
+
const scopeCheck = secret ? await validateAppCredentials(app.id, secret, app.tenant).catch(() => void 0) : void 0;
|
|
9132
|
+
const missingScopes = scopeCheck?.missingScopes;
|
|
9133
|
+
const missingJoinScopes = scopeCheck?.missingJoinScopes;
|
|
9134
|
+
return {
|
|
9135
|
+
codexOk: codexProbe.ok,
|
|
9136
|
+
codexVer: codexProbe.version,
|
|
9137
|
+
conn: channel.getConnectionStatus?.()?.state ?? "unknown",
|
|
9138
|
+
bridgeVer: bridgeVersion(),
|
|
9139
|
+
node: process.version,
|
|
9140
|
+
platform: `${process.platform}-${process.arch}`,
|
|
9141
|
+
logStdout: serviceStdoutPath(),
|
|
9142
|
+
logStderr: serviceStderrPath(),
|
|
9143
|
+
configFile: paths.configFile,
|
|
9144
|
+
missingScopes,
|
|
9145
|
+
// 缺失时预选缺失项(精准开通);查不到/全开通时预选全部必需 scope 供核对。
|
|
9146
|
+
scopeGrantUrl: buildScopeGrantUrl(
|
|
9147
|
+
app.id,
|
|
9148
|
+
app.tenant,
|
|
9149
|
+
missingScopes && missingScopes.length ? missingScopes : void 0
|
|
9150
|
+
),
|
|
9151
|
+
missingJoinScopes,
|
|
9152
|
+
// 「加入存量群」按钮恒预选这两项 opt-in scope(它们不在必需清单里)。
|
|
9153
|
+
joinScopeGrantUrl: buildScopeGrantUrl(app.id, app.tenant, JOIN_GROUP_SCOPES)
|
|
9154
|
+
};
|
|
9155
|
+
};
|
|
8918
9156
|
dispatcher.on(DM.menu, ({ evt }) => {
|
|
8919
9157
|
if (dmAdmin(evt.operator?.openId)) freshMenu(evt);
|
|
8920
9158
|
}).on(DM.newProject, ({ evt }) => {
|
|
@@ -8979,41 +9217,15 @@ function createOrchestrator(channel, cfg, fallbackCwd) {
|
|
|
8979
9217
|
if (dmAdmin(evt.operator?.openId)) await patch(evt, buildSettingsCard(cfg));
|
|
8980
9218
|
}).on(DM.doctor, async ({ evt }) => {
|
|
8981
9219
|
if (!dmAdmin(evt.operator?.openId)) return;
|
|
8982
|
-
|
|
8983
|
-
const app = cfg.accounts.app;
|
|
8984
|
-
const secret = await getSecret(secretKeyForApp(app.id)).catch(() => void 0);
|
|
8985
|
-
const scopeCheck = secret ? await validateAppCredentials(app.id, secret, app.tenant).catch(() => void 0) : void 0;
|
|
8986
|
-
const missingScopes = scopeCheck?.missingScopes;
|
|
8987
|
-
const missingJoinScopes = scopeCheck?.missingJoinScopes;
|
|
8988
|
-
const info = {
|
|
8989
|
-
codexOk: codexProbe.ok,
|
|
8990
|
-
codexVer: codexProbe.version,
|
|
8991
|
-
conn: channel.getConnectionStatus?.()?.state ?? "unknown",
|
|
8992
|
-
bridgeVer: bridgeVersion(),
|
|
8993
|
-
node: process.version,
|
|
8994
|
-
platform: `${process.platform}-${process.arch}`,
|
|
8995
|
-
logStdout: serviceStdoutPath(),
|
|
8996
|
-
logStderr: serviceStderrPath(),
|
|
8997
|
-
configFile: paths.configFile,
|
|
8998
|
-
missingScopes,
|
|
8999
|
-
// 缺失时预选缺失项(精准开通);查不到/全开通时预选全部必需 scope 供核对。
|
|
9000
|
-
scopeGrantUrl: buildScopeGrantUrl(
|
|
9001
|
-
app.id,
|
|
9002
|
-
app.tenant,
|
|
9003
|
-
missingScopes && missingScopes.length ? missingScopes : void 0
|
|
9004
|
-
),
|
|
9005
|
-
missingJoinScopes,
|
|
9006
|
-
// 「加入存量群」按钮恒预选这两项 opt-in scope(它们不在必需清单里)。
|
|
9007
|
-
joinScopeGrantUrl: buildScopeGrantUrl(app.id, app.tenant, JOIN_GROUP_SCOPES)
|
|
9008
|
-
};
|
|
9009
|
-
await sendManagedCard(channel, evt.chatId, buildDoctorCard(info), evt.messageId).catch(
|
|
9220
|
+
await sendManagedCard(channel, evt.chatId, buildDoctorCard(await buildDoctorInfo()), evt.messageId).catch(
|
|
9010
9221
|
(err) => log.fail("console", err, { cmd: "doctor" })
|
|
9011
9222
|
);
|
|
9012
9223
|
}).on(DM.reconnect, async ({ evt }) => {
|
|
9013
9224
|
if (!dmAdmin(evt.operator?.openId)) return;
|
|
9014
9225
|
const conn = channel.getConnectionStatus?.()?.state ?? "unknown";
|
|
9015
|
-
await channel
|
|
9016
|
-
|
|
9226
|
+
await sendManagedCard(channel, evt.chatId, buildReconnectCard(conn), evt.messageId).catch(
|
|
9227
|
+
(err) => log.fail("console", err, { cmd: "reconnect" })
|
|
9228
|
+
);
|
|
9017
9229
|
}).on(DM.update, ({ evt }) => {
|
|
9018
9230
|
if (!dmAdmin(evt.operator?.openId)) return;
|
|
9019
9231
|
void (async () => {
|
|
@@ -9120,6 +9332,10 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
9120
9332
|
});
|
|
9121
9333
|
}).on(DM.setTools, ({ evt, value }) => {
|
|
9122
9334
|
applyPref(evt, (p) => p.showToolCalls = value.v === "on");
|
|
9335
|
+
}).on(DM.setShowModel, ({ evt, value }) => {
|
|
9336
|
+
applyPref(evt, (p) => {
|
|
9337
|
+
p.showModel = value.v === "running" ? "running" : value.v === "always" ? "always" : "off";
|
|
9338
|
+
});
|
|
9123
9339
|
}).on(DM.setWatchdog, ({ evt, value }) => {
|
|
9124
9340
|
const n = Number(value.v);
|
|
9125
9341
|
if (Number.isFinite(n)) applyPref(evt, (p) => p.runIdleTimeoutSeconds = n);
|
|
@@ -9213,7 +9429,7 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
9213
9429
|
const name = typeof value.n === "string" ? value.n : "";
|
|
9214
9430
|
patch(evt, async () => {
|
|
9215
9431
|
const p = await getProjectByName(name);
|
|
9216
|
-
if (!p) return buildDmMenuCard();
|
|
9432
|
+
if (!p) return buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() });
|
|
9217
9433
|
return buildAllowlistCard(p, await namesWithOperator(evt, p.allowedUsers ?? []));
|
|
9218
9434
|
});
|
|
9219
9435
|
}).on(DM.addAllowedForm, ({ evt, value }) => {
|
|
@@ -9245,7 +9461,7 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
9245
9461
|
patch(evt, async () => {
|
|
9246
9462
|
await updateProject(name, (p) => ({ allowedUsers: (p.allowedUsers ?? []).filter((x) => x !== id) }));
|
|
9247
9463
|
const fresh = await getProjectByName(name);
|
|
9248
|
-
if (!fresh) return buildDmMenuCard();
|
|
9464
|
+
if (!fresh) return buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() });
|
|
9249
9465
|
return buildAllowlistCard(fresh, await namesWithOperator(evt, fresh.allowedUsers ?? []));
|
|
9250
9466
|
});
|
|
9251
9467
|
}).on(DM.projectSettings, ({ evt, value }) => {
|
|
@@ -9253,14 +9469,14 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
9253
9469
|
const name = typeof value.n === "string" ? value.n : "";
|
|
9254
9470
|
patch(evt, async () => {
|
|
9255
9471
|
const p = await getProjectByName(name);
|
|
9256
|
-
return p ? buildProjectSettingsCard(p, backendDisplayName(p.backend)) : buildDmMenuCard();
|
|
9472
|
+
return p ? buildProjectSettingsCard(p, backendDisplayName(p.backend)) : buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() });
|
|
9257
9473
|
});
|
|
9258
9474
|
}).on(DM.projectTopics, ({ evt, value }) => {
|
|
9259
9475
|
if (!dmAdmin(evt.operator?.openId)) return;
|
|
9260
9476
|
const name = typeof value.n === "string" ? value.n : "";
|
|
9261
9477
|
patch(evt, async () => {
|
|
9262
9478
|
const p = await getProjectByName(name);
|
|
9263
|
-
if (!p) return buildDmMenuCard();
|
|
9479
|
+
if (!p) return buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() });
|
|
9264
9480
|
const sessions2 = (await listSessions()).filter((s) => s.chatId === p.chatId);
|
|
9265
9481
|
return buildProjectTopicsCard(p, sessions2);
|
|
9266
9482
|
});
|
|
@@ -9270,7 +9486,7 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
9270
9486
|
const on = value.v === "on";
|
|
9271
9487
|
patch(evt, async () => {
|
|
9272
9488
|
const r = await performSetNoMention({ projectName: name, on });
|
|
9273
|
-
if (!r.ok) return buildDmMenuCard();
|
|
9489
|
+
if (!r.ok) return buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() });
|
|
9274
9490
|
return buildProjectSettingsCard(r.project, backendDisplayName(r.project.backend));
|
|
9275
9491
|
});
|
|
9276
9492
|
}).on(DM.setAutoCompactDm, ({ evt, value }) => {
|
|
@@ -9279,7 +9495,7 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
9279
9495
|
const on = value.v === "on";
|
|
9280
9496
|
patch(evt, async () => {
|
|
9281
9497
|
const r = await performSetAutoCompact({ projectName: name, on, evictLiveSessionsForChat });
|
|
9282
|
-
if (!r.ok) return buildDmMenuCard();
|
|
9498
|
+
if (!r.ok) return buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() });
|
|
9283
9499
|
log.info("console", "project-autocompact", { project: name, on });
|
|
9284
9500
|
return buildProjectSettingsCard(r.project, backendDisplayName(r.project.backend));
|
|
9285
9501
|
});
|
|
@@ -9288,7 +9504,7 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
9288
9504
|
const name = typeof value.n === "string" ? value.n : "";
|
|
9289
9505
|
patch(evt, async () => {
|
|
9290
9506
|
const p = await getProjectByName(name);
|
|
9291
|
-
return p ? buildPermissionCard(p) : buildDmMenuCard();
|
|
9507
|
+
return p ? buildPermissionCard(p) : buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() });
|
|
9292
9508
|
});
|
|
9293
9509
|
}).on(DM.permissionSubmit, ({ evt, value, formValue }) => {
|
|
9294
9510
|
if (!dmAdmin(evt.operator?.openId)) return;
|
|
@@ -9434,6 +9650,7 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
9434
9650
|
firstRec = void 0;
|
|
9435
9651
|
const turnModel = rec?.model ?? opts.model;
|
|
9436
9652
|
const turnEffort = rec?.effort ?? opts.effort;
|
|
9653
|
+
const modelDisp = getModelDisplay(cfg);
|
|
9437
9654
|
const run = opts.thread.runStreamed(turnInput, { model: turnModel, effort: turnEffort });
|
|
9438
9655
|
const turnStartAt = Date.now();
|
|
9439
9656
|
state.run = run;
|
|
@@ -9443,7 +9660,9 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
9443
9660
|
const rc = {
|
|
9444
9661
|
rs: render.snapshot(),
|
|
9445
9662
|
requesterOpenId: opts.requesterOpenId,
|
|
9446
|
-
showTools: render.showTools
|
|
9663
|
+
showTools: render.showTools,
|
|
9664
|
+
// 模型显示档位:footnote 本轮 model·推理强度;always 档终态卡也保留。
|
|
9665
|
+
...modelDisp !== "off" && turnModel ? { model: turnModel, effort: turnEffort, modelOnTerminal: modelDisp === "always" } : {}
|
|
9447
9666
|
};
|
|
9448
9667
|
const adoptThreadId = async (messageId) => {
|
|
9449
9668
|
if (activeKey.startsWith("pending:")) {
|
|
@@ -9722,7 +9941,14 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
9722
9941
|
const startTurn = () => {
|
|
9723
9942
|
const render = new RunRender();
|
|
9724
9943
|
render.showTools = getShowToolCalls(cfg);
|
|
9725
|
-
const
|
|
9944
|
+
const goalModelDisp = getModelDisplay(cfg);
|
|
9945
|
+
const rc = {
|
|
9946
|
+
rs: render.snapshot(),
|
|
9947
|
+
requesterOpenId: opts.requesterOpenId,
|
|
9948
|
+
showTools: render.showTools,
|
|
9949
|
+
goalControls: true,
|
|
9950
|
+
...goalModelDisp !== "off" && opts.model ? { model: opts.model, effort: opts.effort, modelOnTerminal: goalModelDisp === "always" } : {}
|
|
9951
|
+
};
|
|
9726
9952
|
return { render, rc, stream: null, cardMsgId: null };
|
|
9727
9953
|
};
|
|
9728
9954
|
const ensureCard = async (ctx) => {
|
|
@@ -10089,9 +10315,60 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
10089
10315
|
}).catch(() => void 0);
|
|
10090
10316
|
return;
|
|
10091
10317
|
}
|
|
10092
|
-
|
|
10093
|
-
|
|
10094
|
-
|
|
10318
|
+
const sendDm = (c) => sendManagedCard(channel, op, c, void 0, false, "open_id");
|
|
10319
|
+
try {
|
|
10320
|
+
switch (evt.eventKey) {
|
|
10321
|
+
case DM.newProject:
|
|
10322
|
+
await sendDm(buildNewProjectFormCard({ backends: backendOptionsFor("full") }));
|
|
10323
|
+
break;
|
|
10324
|
+
case DM.projects:
|
|
10325
|
+
await sendDm(await renderProjectList());
|
|
10326
|
+
break;
|
|
10327
|
+
case DM.settings:
|
|
10328
|
+
await sendDm(buildSettingsCard(cfg));
|
|
10329
|
+
break;
|
|
10330
|
+
case DM.doctor:
|
|
10331
|
+
await sendDm(buildDoctorCard(await buildDoctorInfo()));
|
|
10332
|
+
break;
|
|
10333
|
+
case DM.reconnect:
|
|
10334
|
+
await sendDm(buildReconnectCard(channel.getConnectionStatus?.()?.state ?? "unknown"));
|
|
10335
|
+
break;
|
|
10336
|
+
case DM.usage: {
|
|
10337
|
+
const { messageId } = await sendDm(buildUsageCard({ phase: "loading" }));
|
|
10338
|
+
let state;
|
|
10339
|
+
try {
|
|
10340
|
+
state = { phase: "ready", data: await fetchUsageBundle(false) };
|
|
10341
|
+
} catch (e) {
|
|
10342
|
+
log.fail("console", e, { phase: "usage", via: "menu" });
|
|
10343
|
+
state = {
|
|
10344
|
+
phase: "error",
|
|
10345
|
+
kind: e instanceof UsageError ? e.kind : "transient",
|
|
10346
|
+
message: e instanceof Error ? e.message : String(e)
|
|
10347
|
+
};
|
|
10348
|
+
}
|
|
10349
|
+
const ok = await updateManagedCard(channel, messageId, buildUsageCard(state)).catch(() => false);
|
|
10350
|
+
if (!ok) await sendDm(buildUsageCard(state));
|
|
10351
|
+
break;
|
|
10352
|
+
}
|
|
10353
|
+
case DM.update: {
|
|
10354
|
+
const { messageId } = await sendDm(buildUpdateCard({ phase: "checking" }));
|
|
10355
|
+
const current = currentVersion();
|
|
10356
|
+
const latest = await latestVersion().catch(() => null);
|
|
10357
|
+
const hasUpdate = !!latest && isNewer(latest, current);
|
|
10358
|
+
log.info("console", "update-check", { current, latest, hasUpdate, via: "menu" });
|
|
10359
|
+
await updateManagedCard(
|
|
10360
|
+
channel,
|
|
10361
|
+
messageId,
|
|
10362
|
+
buildUpdateCard({ phase: "checked", current, latest, hasUpdate, dev: isDevSource() })
|
|
10363
|
+
).catch((e) => log.fail("console", e, { phase: "update-check", via: "menu" }));
|
|
10364
|
+
break;
|
|
10365
|
+
}
|
|
10366
|
+
default:
|
|
10367
|
+
await sendDm(buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() }));
|
|
10368
|
+
}
|
|
10369
|
+
} catch (err) {
|
|
10370
|
+
log.fail("console", err, { cmd: "menu-card", key: evt.eventKey });
|
|
10371
|
+
}
|
|
10095
10372
|
};
|
|
10096
10373
|
const reaper = setInterval(() => {
|
|
10097
10374
|
const now = Date.now();
|
|
@@ -10355,7 +10632,7 @@ function withOwnerAdmin(base, ownerOpenId) {
|
|
|
10355
10632
|
|
|
10356
10633
|
// src/admin/host.ts
|
|
10357
10634
|
import { readdir as readdir4, stat as stat4 } from "fs/promises";
|
|
10358
|
-
import { dirname as
|
|
10635
|
+
import { dirname as dirname12, join as join18, resolve as resolve7 } from "path";
|
|
10359
10636
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
10360
10637
|
import { arch, platform as platform2, release } from "os";
|
|
10361
10638
|
function toDaemonStatus(opts) {
|
|
@@ -10407,7 +10684,7 @@ async function collectHostDoctor(logsDir2 = join18(paths.appDir, "logs")) {
|
|
|
10407
10684
|
};
|
|
10408
10685
|
}
|
|
10409
10686
|
function resolveCliBinPath3() {
|
|
10410
|
-
const distDir =
|
|
10687
|
+
const distDir = dirname12(fileURLToPath5(import.meta.url));
|
|
10411
10688
|
return resolve7(distDir, "..", "bin", "feishu-codex-bridge.mjs");
|
|
10412
10689
|
}
|
|
10413
10690
|
function buildDaemonControlCommand(action, binPath = resolveCliBinPath3(), nodePath = process.execPath) {
|
|
@@ -10457,7 +10734,7 @@ function createAdminService(deps = {}) {
|
|
|
10457
10734
|
try {
|
|
10458
10735
|
const raw = await readFile11(botPaths(botId).processesFile, "utf8");
|
|
10459
10736
|
const rec = JSON.parse(raw);
|
|
10460
|
-
if (typeof rec.pid === "number" &&
|
|
10737
|
+
if (typeof rec.pid === "number" && isAlive2(rec.pid)) {
|
|
10461
10738
|
return { running: true, pid: rec.pid, startedAt: rec.startedAt };
|
|
10462
10739
|
}
|
|
10463
10740
|
} catch {
|
|
@@ -10853,7 +11130,7 @@ async function probeAllBackends() {
|
|
|
10853
11130
|
function createReadonlyAdminService(deps = {}) {
|
|
10854
11131
|
return createAdminService({ startDaemon: deps.startDaemon, applyUpdate: deps.applyUpdate, readonlyPreview: true });
|
|
10855
11132
|
}
|
|
10856
|
-
function
|
|
11133
|
+
function isAlive2(pid) {
|
|
10857
11134
|
try {
|
|
10858
11135
|
process.kill(pid, 0);
|
|
10859
11136
|
return true;
|
|
@@ -10862,66 +11139,6 @@ function isAlive(pid) {
|
|
|
10862
11139
|
}
|
|
10863
11140
|
}
|
|
10864
11141
|
|
|
10865
|
-
// src/web/discovery.ts
|
|
10866
|
-
import { randomUUID as randomUUID4 } from "crypto";
|
|
10867
|
-
import { mkdirSync as mkdirSync2, readFileSync as readFileSync5, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
10868
|
-
import { dirname as dirname12 } from "path";
|
|
10869
|
-
function publishWebConsole(rec, file = paths.webConsoleFile) {
|
|
10870
|
-
mkdirSync2(dirname12(file), { recursive: true });
|
|
10871
|
-
try {
|
|
10872
|
-
unlinkSync(file);
|
|
10873
|
-
} catch {
|
|
10874
|
-
}
|
|
10875
|
-
writeFileSync2(file, `${JSON.stringify(rec, null, 2)}
|
|
10876
|
-
`, { mode: 384 });
|
|
10877
|
-
}
|
|
10878
|
-
function readWebConsole(file = paths.webConsoleFile) {
|
|
10879
|
-
try {
|
|
10880
|
-
const rec = JSON.parse(readFileSync5(file, "utf8"));
|
|
10881
|
-
if (typeof rec.port !== "number" || typeof rec.token !== "string" || rec.token === "" || typeof rec.pid !== "number") {
|
|
10882
|
-
return void 0;
|
|
10883
|
-
}
|
|
10884
|
-
if (!isAlive2(rec.pid)) return void 0;
|
|
10885
|
-
return rec;
|
|
10886
|
-
} catch {
|
|
10887
|
-
return void 0;
|
|
10888
|
-
}
|
|
10889
|
-
}
|
|
10890
|
-
function clearWebConsole(file = paths.webConsoleFile) {
|
|
10891
|
-
try {
|
|
10892
|
-
const rec = JSON.parse(readFileSync5(file, "utf8"));
|
|
10893
|
-
if (rec.pid === process.pid) unlinkSync(file);
|
|
10894
|
-
} catch {
|
|
10895
|
-
}
|
|
10896
|
-
}
|
|
10897
|
-
function stableWebConsoleToken(file = paths.webTokenFile) {
|
|
10898
|
-
try {
|
|
10899
|
-
const t = readFileSync5(file, "utf8").trim();
|
|
10900
|
-
if (t) return t;
|
|
10901
|
-
} catch {
|
|
10902
|
-
}
|
|
10903
|
-
const token = randomUUID4();
|
|
10904
|
-
try {
|
|
10905
|
-
mkdirSync2(dirname12(file), { recursive: true });
|
|
10906
|
-
try {
|
|
10907
|
-
unlinkSync(file);
|
|
10908
|
-
} catch {
|
|
10909
|
-
}
|
|
10910
|
-
writeFileSync2(file, `${token}
|
|
10911
|
-
`, { mode: 384 });
|
|
10912
|
-
} catch {
|
|
10913
|
-
}
|
|
10914
|
-
return token;
|
|
10915
|
-
}
|
|
10916
|
-
function isAlive2(pid) {
|
|
10917
|
-
try {
|
|
10918
|
-
process.kill(pid, 0);
|
|
10919
|
-
return true;
|
|
10920
|
-
} catch (err) {
|
|
10921
|
-
return err.code === "EPERM";
|
|
10922
|
-
}
|
|
10923
|
-
}
|
|
10924
|
-
|
|
10925
11142
|
// src/cli/commands/daemon-control.ts
|
|
10926
11143
|
function spawnDaemonControl(action) {
|
|
10927
11144
|
const { command, args } = buildDaemonControlCommand(action);
|