@modelzen/feishu-codex-bridge 0.6.2 → 0.6.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/README.md +72 -263
- package/dist/cli.js +644 -70
- package/dist/index.d.ts +8 -0
- package/dist/index.js +12 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -57,6 +57,18 @@ var init_paths = __esm({
|
|
|
57
57
|
get processesFile() {
|
|
58
58
|
return join(currentBotDir, "processes.json");
|
|
59
59
|
},
|
|
60
|
+
/** 云文档评论 @bot 的可编辑提示词 master 文件(当前 bot)。用户直接编辑这一份,
|
|
61
|
+
* 桥在每条评论运行前把它同步进该文档的评论工作目录(AGENTS.md / CLAUDE.md)。
|
|
62
|
+
* 首次缺失时由 bot/comments.ts 用内置默认模板自动落地。 */
|
|
63
|
+
get commentInstructionsFile() {
|
|
64
|
+
return join(currentBotDir, "comment-instructions.md");
|
|
65
|
+
},
|
|
66
|
+
/** 评论工作目录根(**当前 bot**):每个被评论文档一个 `comment-<type>-<token>` 子目录,
|
|
67
|
+
* 放同步进去的 AGENTS.md / CLAUDE.md。放 per-bot 目录下,与其它 bot 隔离——否则
|
|
68
|
+
* 编辑提示词时的「全量同步」会越界改到别的 bot 的评论目录。 */
|
|
69
|
+
get commentsRootDir() {
|
|
70
|
+
return join(currentBotDir, "comments");
|
|
71
|
+
},
|
|
60
72
|
/**
|
|
61
73
|
* Local CLI hook IPC endpoint for the current bot. macOS/Linux use a Unix
|
|
62
74
|
* domain socket file; Windows has none, so Node maps a `\\.\pipe\…` path to a
|
|
@@ -218,6 +230,9 @@ function resolveCliBridgeTarget(cfg) {
|
|
|
218
230
|
function canEnableCliBridge(cfg) {
|
|
219
231
|
return resolveCliBridgeTarget(cfg) ? { ok: true } : { ok: false, reason: "missing_owner" };
|
|
220
232
|
}
|
|
233
|
+
function getCommentsConfig(cfg) {
|
|
234
|
+
return cfg.preferences?.comments ?? {};
|
|
235
|
+
}
|
|
221
236
|
var RUN_IDLE_TIMEOUT_MIN_SEC, RUN_IDLE_TIMEOUT_MAX_SEC;
|
|
222
237
|
var init_schema = __esm({
|
|
223
238
|
"src/config/schema.ts"() {
|
|
@@ -630,6 +645,7 @@ var init_logger = __esm({
|
|
|
630
645
|
function card(elements, opts = {}) {
|
|
631
646
|
const config = { update_multi: true };
|
|
632
647
|
if (opts.forward === false) config.enable_forward = false;
|
|
648
|
+
if (opts.widthMode) config.width_mode = opts.widthMode;
|
|
633
649
|
if (opts.streaming) {
|
|
634
650
|
config.streaming_mode = true;
|
|
635
651
|
config.streaming_config = {
|
|
@@ -772,9 +788,13 @@ function input(opts) {
|
|
|
772
788
|
return {
|
|
773
789
|
tag: "input",
|
|
774
790
|
name: opts.name,
|
|
791
|
+
...opts.inputType ? { input_type: opts.inputType } : {},
|
|
792
|
+
...opts.rows ? { rows: opts.rows, auto_resize: true } : {},
|
|
793
|
+
...opts.width !== void 0 ? { width: opts.width } : {},
|
|
775
794
|
...opts.label ? { label: { tag: "plain_text", content: opts.label } } : {},
|
|
776
795
|
...opts.placeholder ? { placeholder: { tag: "plain_text", content: opts.placeholder } } : {},
|
|
777
796
|
...opts.value ? { default_value: opts.value } : {},
|
|
797
|
+
...opts.maxLength ? { max_length: opts.maxLength } : {},
|
|
778
798
|
required: Boolean(opts.required)
|
|
779
799
|
};
|
|
780
800
|
}
|
|
@@ -1995,13 +2015,13 @@ __export(cli_bridge_exports, {
|
|
|
1995
2015
|
selectCliBridgeHookBot: () => selectCliBridgeHookBot,
|
|
1996
2016
|
shouldStartCliBridge: () => shouldStartCliBridge
|
|
1997
2017
|
});
|
|
1998
|
-
import { join as
|
|
2018
|
+
import { join as join20 } from "path";
|
|
1999
2019
|
async function selectCliBridgeHookBot(reg, opts = {}) {
|
|
2000
2020
|
const requested = opts.requested?.trim();
|
|
2001
2021
|
if (requested) {
|
|
2002
2022
|
return findBot(reg, requested) ?? { name: requested, appId: requested, tenant: "feishu", createdAt: 0 };
|
|
2003
2023
|
}
|
|
2004
|
-
const loadConfigForBot = opts.loadConfigForBot ?? ((appId) => loadConfig(
|
|
2024
|
+
const loadConfigForBot = opts.loadConfigForBot ?? ((appId) => loadConfig(join20(botDir(appId), "config.json")));
|
|
2005
2025
|
const current = currentBot(reg);
|
|
2006
2026
|
const active = activeBots(reg);
|
|
2007
2027
|
const candidates = active.length > 0 ? active : current ? [current] : reg.bots;
|
|
@@ -4166,6 +4186,8 @@ var ClaudeAgentThread = class {
|
|
|
4166
4186
|
...toSdkEffort(cfg.effort) ? { effort: toSdkEffort(cfg.effort) } : {},
|
|
4167
4187
|
...cfg.resume ? { resume: cfg.sessionId } : { sessionId: cfg.sessionId },
|
|
4168
4188
|
...cfg.systemPromptAppend ? { systemPrompt: { type: "preset", preset: "claude_code", append: cfg.systemPromptAppend } } : {},
|
|
4189
|
+
...cfg.settingSources ? { settingSources: cfg.settingSources } : {},
|
|
4190
|
+
...cfg.env ? { env: cfg.env } : {},
|
|
4169
4191
|
// permission tier (permissionMode / sandbox / canUseTool / disallowedTools)
|
|
4170
4192
|
...cfg.permission,
|
|
4171
4193
|
stderr: (d) => {
|
|
@@ -4449,6 +4471,13 @@ var ClaudeAgentThread = class {
|
|
|
4449
4471
|
|
|
4450
4472
|
// src/agent/claude-agent/backend.ts
|
|
4451
4473
|
var SDK_PKG = "@anthropic-ai/claude-agent-sdk";
|
|
4474
|
+
var BRIDGE_SETTING_SOURCES = ["user", "project"];
|
|
4475
|
+
function bridgeClaudeEnv() {
|
|
4476
|
+
const base = {};
|
|
4477
|
+
for (const [k2, v] of Object.entries(process.env)) if (typeof v === "string") base[k2] = v;
|
|
4478
|
+
base.FEISHU_CODEX_BRIDGE = "1";
|
|
4479
|
+
return base;
|
|
4480
|
+
}
|
|
4452
4481
|
var sdkPromise;
|
|
4453
4482
|
function loadSdk() {
|
|
4454
4483
|
sdkPromise ??= loadBackendDep(SDK_PKG);
|
|
@@ -4531,6 +4560,8 @@ var ClaudeAgentBackend = class {
|
|
|
4531
4560
|
effort: opts.effort,
|
|
4532
4561
|
permission: permissionOptions(opts.mode, opts.network, opts.cwd),
|
|
4533
4562
|
systemPromptAppend: BRIDGE_DEVELOPER_INSTRUCTIONS,
|
|
4563
|
+
settingSources: BRIDGE_SETTING_SOURCES,
|
|
4564
|
+
env: bridgeClaudeEnv(),
|
|
4534
4565
|
query: sdk.query
|
|
4535
4566
|
});
|
|
4536
4567
|
}
|
|
@@ -4544,6 +4575,8 @@ var ClaudeAgentBackend = class {
|
|
|
4544
4575
|
effort: opts.effort,
|
|
4545
4576
|
permission: permissionOptions(opts.mode, opts.network, opts.cwd),
|
|
4546
4577
|
systemPromptAppend: BRIDGE_DEVELOPER_INSTRUCTIONS,
|
|
4578
|
+
settingSources: BRIDGE_SETTING_SOURCES,
|
|
4579
|
+
env: bridgeClaudeEnv(),
|
|
4547
4580
|
query: sdk.query
|
|
4548
4581
|
});
|
|
4549
4582
|
}
|
|
@@ -5633,6 +5666,8 @@ var DM = {
|
|
|
5633
5666
|
joinGroupSubmit: "dm.joinGroup.submit",
|
|
5634
5667
|
projects: "dm.projects",
|
|
5635
5668
|
settings: "dm.settings",
|
|
5669
|
+
// ☕ 咖啡一下(离开接管):从全局设置卡进入的二级卡片(仿云文档评论那样的子卡入口)
|
|
5670
|
+
coffeeSettings: "dm.coffee.settings",
|
|
5636
5671
|
doctor: "dm.doctor",
|
|
5637
5672
|
reconnect: "dm.reconnect",
|
|
5638
5673
|
update: "dm.update",
|
|
@@ -5670,15 +5705,29 @@ var DM = {
|
|
|
5670
5705
|
setNoMentionDm: "dm.proj.noMention",
|
|
5671
5706
|
// 🗜️ 自动压缩:项目级开关(同群设置里的那个,DM 里也能改),按钮携带项目名 n
|
|
5672
5707
|
setAutoCompactDm: "dm.proj.autoCompact",
|
|
5708
|
+
// 🤖 默认模型/强度:新话题的起始模型 + 推理强度(选完提交的下拉表单子卡,仿权限卡)
|
|
5709
|
+
modelDefault: "dm.proj.modelDefault",
|
|
5710
|
+
modelDefaultSubmit: "dm.proj.modelDefault.submit",
|
|
5673
5711
|
// 🔐 权限:codex 沙箱档位(管理员档 + 普通用户档)+ 联网,做成下拉表单(选+提交)
|
|
5674
5712
|
permission: "dm.proj.perm",
|
|
5675
|
-
permissionSubmit: "dm.proj.perm.submit"
|
|
5713
|
+
permissionSubmit: "dm.proj.perm.submit",
|
|
5676
5714
|
// 🧠 后端 backend/backendSubmit 已移除:后端改为「创建时选定、运行时固定、不支持切换」,
|
|
5677
5715
|
// 新建卡选后端见 newProjectSubmit;项目设置卡只读展示。
|
|
5716
|
+
// 📝 云文档评论 @bot 全局设置:后端按钮(级联)→模型/强度下拉表单提交;提示词在卡内编辑。
|
|
5717
|
+
commentSettings: "dm.comment.settings",
|
|
5718
|
+
commentSetBackend: "dm.comment.setBackend",
|
|
5719
|
+
commentSubmit: "dm.comment.submit",
|
|
5720
|
+
commentEditPrompt: "dm.comment.editPrompt",
|
|
5721
|
+
commentPromptSubmit: "dm.comment.promptSubmit",
|
|
5722
|
+
commentResetPrompt: "dm.comment.resetPrompt"
|
|
5678
5723
|
};
|
|
5679
5724
|
var GS = {
|
|
5680
5725
|
setNoMention: "gs.noMention",
|
|
5681
|
-
setAutoCompact: "gs.autoCompact"
|
|
5726
|
+
setAutoCompact: "gs.autoCompact",
|
|
5727
|
+
// 🤖 默认模型/强度:群内 /settings 的镜像入口(open=进子卡,submit=保存,settings=返回群设置)
|
|
5728
|
+
settings: "gs.settings",
|
|
5729
|
+
modelDefault: "gs.modelDefault",
|
|
5730
|
+
modelDefaultSubmit: "gs.modelDefault.submit"
|
|
5682
5731
|
};
|
|
5683
5732
|
function kindLabel(kind) {
|
|
5684
5733
|
return kind === "single" ? "\u{1F4AC} \u5355\u4F1A\u8BDD\u7FA4" : "\u{1F465} \u591A\u8BDD\u9898\u7FA4";
|
|
@@ -6055,15 +6104,19 @@ function buildNewProjectDoneCard(p) {
|
|
|
6055
6104
|
return card(elements, { header: { title, template: "green" } });
|
|
6056
6105
|
}
|
|
6057
6106
|
var PROJECT_TOPICS_MAX = 50;
|
|
6058
|
-
|
|
6107
|
+
var PROJECT_LIST_PAGE_SIZE = 8;
|
|
6108
|
+
function buildProjectListCard(projects, sessionsByChat = /* @__PURE__ */ new Map(), page = 0) {
|
|
6059
6109
|
if (projects.length === 0) {
|
|
6060
6110
|
return card(
|
|
6061
6111
|
[md("\u8FD8\u6CA1\u6709\u9879\u76EE\u3002\u70B9 **\u2795 \u65B0\u5EFA\u9879\u76EE** \u6216\u76F4\u63A5\u53D1\u6211\u4E00\u4E2A\u9879\u76EE\u540D\u3002"), actions([button("\u2B05\uFE0F \u83DC\u5355", { a: DM.menu })])],
|
|
6062
6112
|
{ header: { title: "\u{1F4C1} \u9879\u76EE\u5217\u8868", template: "wathet" } }
|
|
6063
6113
|
);
|
|
6064
6114
|
}
|
|
6115
|
+
const pageCount = Math.ceil(projects.length / PROJECT_LIST_PAGE_SIZE);
|
|
6116
|
+
const cur = Math.min(Math.max(Math.trunc(page) || 0, 0), pageCount - 1);
|
|
6117
|
+
const start = cur * PROJECT_LIST_PAGE_SIZE;
|
|
6065
6118
|
const elements = [];
|
|
6066
|
-
for (const p of projects) {
|
|
6119
|
+
for (const p of projects.slice(start, start + PROJECT_LIST_PAGE_SIZE)) {
|
|
6067
6120
|
const topicCount = (p.chatId ? sessionsByChat.get(p.chatId) : void 0)?.length ?? 0;
|
|
6068
6121
|
const dir = `\u{1F4C2} \`${p.cwd}\`${p.branch && p.branch !== "\u2014" ? ` \u{1F33F} ${p.branch}` : ""}`;
|
|
6069
6122
|
const meta = p.chatId ? `${kindLabel(p.kind)}${(p.origin ?? "created") === "joined" ? " \xB7 \u{1F517}\u5DF2\u52A0\u5165" : ""} \xB7 \u514D@\uFF1A${p.noMention ?? defaultNoMention(p) ? "\u5F00" : "\u5173"}` : "\u26A0\uFE0F \u672A\u7ED1\u5B9A\u7FA4";
|
|
@@ -6078,8 +6131,14 @@ ${meta}`));
|
|
|
6078
6131
|
elements.push(actions(row));
|
|
6079
6132
|
elements.push(hr());
|
|
6080
6133
|
}
|
|
6081
|
-
elements.push(
|
|
6082
|
-
|
|
6134
|
+
elements.push(
|
|
6135
|
+
note(pageCount > 1 ? `\u5171 ${projects.length} \u4E2A\u9879\u76EE \xB7 \u7B2C ${cur + 1}/${pageCount} \u9875` : `\u5171 ${projects.length} \u4E2A\u9879\u76EE`)
|
|
6136
|
+
);
|
|
6137
|
+
const nav = [];
|
|
6138
|
+
if (cur > 0) nav.push(button("\u2B05\uFE0F \u4E0A\u4E00\u9875", { a: DM.projects, p: cur - 1 }));
|
|
6139
|
+
if (cur < pageCount - 1) nav.push(button("\u4E0B\u4E00\u9875 \u27A1\uFE0F", { a: DM.projects, p: cur + 1 }));
|
|
6140
|
+
nav.push(button("\u2B05\uFE0F \u83DC\u5355", { a: DM.menu }));
|
|
6141
|
+
elements.push(actions(nav));
|
|
6083
6142
|
return card(elements, { header: { title: "\u{1F4C1} \u9879\u76EE\u5217\u8868", template: "wathet" } });
|
|
6084
6143
|
}
|
|
6085
6144
|
function buildProjectTopicsCard(project, sessions) {
|
|
@@ -6132,7 +6191,7 @@ function settingItem(name, desc, actionId, current, opts) {
|
|
|
6132
6191
|
actions(opts.map((o) => button(o.label, { a: actionId, v: o.value }, o.value === current ? "primary" : "default")))
|
|
6133
6192
|
];
|
|
6134
6193
|
}
|
|
6135
|
-
function buildSettingsCard(cfg
|
|
6194
|
+
function buildSettingsCard(cfg) {
|
|
6136
6195
|
const watchdogSec = cfg.preferences?.runIdleTimeoutSeconds ?? 120;
|
|
6137
6196
|
return card(
|
|
6138
6197
|
[
|
|
@@ -6190,13 +6249,169 @@ function buildSettingsCard(cfg, localAgents = []) {
|
|
|
6190
6249
|
{ label: "20", value: "20" }
|
|
6191
6250
|
]
|
|
6192
6251
|
),
|
|
6193
|
-
|
|
6252
|
+
hr(),
|
|
6253
|
+
settingSection("\u2615 \u5496\u5561\u4E00\u4E0B"),
|
|
6254
|
+
note("\u53BB\u5012\u676F\u5496\u5561\u7684\u5DE5\u592B\uFF0C\u6211\u66FF\u4F60\u76EF\u7740\u672C\u673A\u7684 Claude Code / Codex\u2014\u2014\u5B83\u8981\u5BA1\u6279\u3001\u8981\u95EE\u4F60\u3001\u6216\u8DD1\u5B8C\u4E86\uFF0C\u90FD\u63A8\u5230\u8FD9\u4E2A\u79C1\u804A\u3002\u542B\u901A\u77E5\u8303\u56F4\u3001\u8F6C\u53D1\u540E\u7AEF\u3001\u79BB\u5F00\u4FDD\u6D3B\u3001hooks \u4FEE\u590D\u3002"),
|
|
6255
|
+
actions([button("\u8BBE\u7F6E\u5496\u5561\u4E00\u4E0B / \u901A\u77E5 / \u4FDD\u6D3B / hooks", { a: DM.coffeeSettings }, "primary")]),
|
|
6256
|
+
hr(),
|
|
6257
|
+
settingSection("\u{1F4DD} \u4E91\u6587\u6863\u8BC4\u8BBA"),
|
|
6258
|
+
note("\u5728\u98DE\u4E66\u4E91\u6587\u6863\uFF08\u6587\u6863 / \u8868\u683C / \u591A\u7EF4\u8868\u683C\uFF0C\u542B wiki\uFF09\u7684\u8BC4\u8BBA\u91CC @\u6211\uFF0C\u6211\u8BFB\u8BC4\u8BBA\u3001\u8DD1 agent\u3001\u628A\u7B54\u6848\u8D34\u56DE\u8BC4\u8BBA\u3002\u53EF\u8BBE\u7F6E\u8BC4\u8BBA\u54CD\u5E94\u7528\u7684\u540E\u7AEF agent / \u6A21\u578B / \u63A8\u7406\u5F3A\u5EA6\uFF0C\u4EE5\u53CA\u81EA\u5B9A\u4E49\u63D0\u793A\u8BCD\uFF08\u5168\u5C40\uFF0C\u4E0D\u5206\u9879\u76EE\uFF1B\u4EC5\u7BA1\u7406\u5458\u53EF @\uFF09\u3002"),
|
|
6259
|
+
actions([button("\u8BBE\u7F6E\u540E\u7AEF / \u6A21\u578B / \u5F3A\u5EA6 / \u63D0\u793A\u8BCD", { a: DM.commentSettings }, "primary")]),
|
|
6194
6260
|
hr(),
|
|
6195
6261
|
actions([button("\u{1F46E} \u7BA1\u7406\u5458", { a: DM.admins }), button("\u2B05\uFE0F \u83DC\u5355", { a: DM.menu })])
|
|
6196
6262
|
],
|
|
6197
6263
|
{ header: { title: "\u2699\uFE0F \u5168\u5C40\u8BBE\u7F6E", template: "blue" } }
|
|
6198
6264
|
);
|
|
6199
6265
|
}
|
|
6266
|
+
function buildCoffeeSettingsCard(section) {
|
|
6267
|
+
return card(
|
|
6268
|
+
[
|
|
6269
|
+
...section.slice(1),
|
|
6270
|
+
// 去掉为「内联进主卡」而加的开头 hr()
|
|
6271
|
+
hr(),
|
|
6272
|
+
actions([button("\u2B05\uFE0F \u8FD4\u56DE\u8BBE\u7F6E", { a: DM.settings })])
|
|
6273
|
+
],
|
|
6274
|
+
{ header: { title: "\u2615 \u5496\u5561\u4E00\u4E0B", template: "blue" } }
|
|
6275
|
+
);
|
|
6276
|
+
}
|
|
6277
|
+
var LARK_CLI_DOC_URL = "https://bytedance.larkoffice.com/wiki/ILuTww7Xcimb6GkhH0mcK2f4nS7";
|
|
6278
|
+
function buildCommentSettingsCard(cfg, backendOptions, models, notice) {
|
|
6279
|
+
const comments = cfg.preferences?.comments ?? {};
|
|
6280
|
+
const visible = models.filter((m) => !m.hidden);
|
|
6281
|
+
const curBackend = comments.backend && backendOptions.some((b) => b.id === comments.backend) ? comments.backend : backendOptions.find((b) => b.id === DEFAULT_BACKEND_ID)?.id ?? backendOptions[0]?.id ?? DEFAULT_BACKEND_ID;
|
|
6282
|
+
const explicit = comments.model ? visible.find((m) => m.id === comments.model) : void 0;
|
|
6283
|
+
const curModel = explicit ?? visible.find((m) => m.isDefault) ?? visible[0];
|
|
6284
|
+
const unionEfforts = EFFORT_ORDER.filter((e) => visible.some((m) => (m.supportedEfforts ?? []).includes(e)));
|
|
6285
|
+
const curEffort = comments.effort && (curModel?.supportedEfforts ?? []).includes(comments.effort) ? comments.effort : curModel?.defaultEffort;
|
|
6286
|
+
const canPickModel = visible.length > 1;
|
|
6287
|
+
const canPickEffort = unionEfforts.length > 0;
|
|
6288
|
+
const els = [
|
|
6289
|
+
...notice ? [md(notice)] : [],
|
|
6290
|
+
md("**\u{1F4DD} \u4E91\u6587\u6863\u8BC4\u8BBA @bot**"),
|
|
6291
|
+
note("\u8BC4\u8BBA\u91CC @\u6211\u65F6\u7528\u7684\u540E\u7AEF / \u6A21\u578B / \u63A8\u7406\u5F3A\u5EA6\u3002\u53EA\u5F71\u54CD\u4E4B\u540E\u65B0\u5EFA\u7684\u8BC4\u8BBA\u3002"),
|
|
6292
|
+
hr()
|
|
6293
|
+
];
|
|
6294
|
+
if (backendOptions.length > 1) {
|
|
6295
|
+
els.push(
|
|
6296
|
+
md("\u{1F9E0} **\u540E\u7AEF**"),
|
|
6297
|
+
actions(
|
|
6298
|
+
backendOptions.map(
|
|
6299
|
+
(b) => button(b.label, { a: DM.commentSetBackend, v: b.id }, b.id === curBackend ? "primary" : "default")
|
|
6300
|
+
)
|
|
6301
|
+
)
|
|
6302
|
+
);
|
|
6303
|
+
} else {
|
|
6304
|
+
els.push(md(`\u{1F9E0} **\u540E\u7AEF**\uFF1A${backendOptions[0]?.label ?? curBackend}`));
|
|
6305
|
+
}
|
|
6306
|
+
if (canPickModel || canPickEffort) {
|
|
6307
|
+
const formEls = [];
|
|
6308
|
+
if (canPickModel) {
|
|
6309
|
+
formEls.push(
|
|
6310
|
+
md("\u{1F916} **\u6A21\u578B**"),
|
|
6311
|
+
selectMenu({
|
|
6312
|
+
name: "model",
|
|
6313
|
+
placeholder: "\u9009\u62E9\u6A21\u578B",
|
|
6314
|
+
options: visible.map((m) => ({ label: m.displayName, value: m.id })),
|
|
6315
|
+
initial: curModel?.id
|
|
6316
|
+
})
|
|
6317
|
+
);
|
|
6318
|
+
} else {
|
|
6319
|
+
formEls.push(md(`\u{1F916} **\u6A21\u578B**\uFF1A${curModel?.displayName ?? "\u540E\u7AEF\u9ED8\u8BA4"}\uFF08\u8BE5\u540E\u7AEF\u4EC5\u4E00\u4E2A\u6A21\u578B\uFF09`));
|
|
6320
|
+
}
|
|
6321
|
+
if (canPickEffort) {
|
|
6322
|
+
formEls.push(
|
|
6323
|
+
md("\u{1F39A} **\u63A8\u7406\u5F3A\u5EA6**"),
|
|
6324
|
+
selectMenu({
|
|
6325
|
+
name: "effort",
|
|
6326
|
+
placeholder: "\u9009\u62E9\u63A8\u7406\u5F3A\u5EA6",
|
|
6327
|
+
options: unionEfforts.map((e) => ({ label: EFFORT_LABEL[e], value: e })),
|
|
6328
|
+
initial: curEffort
|
|
6329
|
+
})
|
|
6330
|
+
);
|
|
6331
|
+
}
|
|
6332
|
+
formEls.push(actions([submitButton("\u2705 \u4FDD\u5B58\u6A21\u578B / \u5F3A\u5EA6", { a: DM.commentSubmit }, "primary", "submit_comment")]));
|
|
6333
|
+
els.push(form("comment_model_effort", formEls));
|
|
6334
|
+
} else {
|
|
6335
|
+
els.push(note("\u8BE5\u540E\u7AEF\u53EA\u6709\u4E00\u4E2A\u6A21\u578B\u4E14\u4E0D\u8C03\u63A8\u7406\u5F3A\u5EA6\uFF0C\u65E0\u9700\u8BBE\u7F6E\u3002"));
|
|
6336
|
+
}
|
|
6337
|
+
els.push(
|
|
6338
|
+
hr(),
|
|
6339
|
+
md("\u270D\uFE0F **\u63D0\u793A\u8BCD**"),
|
|
6340
|
+
note("\u8BC4\u8BBA @\u6211 \u65F6\u6211\u7684\u89D2\u8272\u4E0E\u56DE\u590D\u89C4\u5219\uFF08\u542B\u600E\u4E48\u8BFB / \u6539\u6587\u6863\uFF09\u3002\u70B9\u5F00\u53EF\u76F4\u63A5\u5728\u5361\u91CC\u7F16\u8F91\u3002"),
|
|
6341
|
+
actions([button("\u7F16\u8F91\u63D0\u793A\u8BCD", { a: DM.commentEditPrompt }, "primary")]),
|
|
6342
|
+
hr(),
|
|
6343
|
+
md("\u{1F4CE} **\u914D\u5408\u98DE\u4E66 CLI**"),
|
|
6344
|
+
note(
|
|
6345
|
+
`\u8BC4\u8BBA\u91CC\u8981**\u8BFB / \u6539\u6587\u6863**\uFF0C\u9760\u98DE\u4E66 CLI\uFF08lark-cli\uFF09\uFF1A\u88C5\u597D\u5E76\u767B\u5F55\u540E\u5373\u53EF\uFF08\u7528\u4F60\u81EA\u5DF1\u7684\u8EAB\u4EFD\u8BFB\u5199\u3001\u5BF9\u81EA\u5DF1\u7684\u6587\u6863\u6709\u6743\u9650\uFF09\u3002Tips\uFF1A\u98DE\u4E66 CLI \u53EF\u4E0E\u672C\u673A\u5668\u4EBA\u590D\u7528\u540C\u4E00\u4E2A App\u3002\u5B89\u88C5\u4E0E\u7528\u6CD5\u89C1 [\u98DE\u4E66 CLI \u6587\u6863](${LARK_CLI_DOC_URL})\u3002`
|
|
6346
|
+
),
|
|
6347
|
+
hr(),
|
|
6348
|
+
actions([button("\u2B05\uFE0F \u8FD4\u56DE\u8BBE\u7F6E", { a: DM.settings })])
|
|
6349
|
+
);
|
|
6350
|
+
return card(els, { header: { title: "\u{1F4DD} \u6587\u6863\u8BC4\u8BBA\u8BBE\u7F6E", template: "blue" } });
|
|
6351
|
+
}
|
|
6352
|
+
function buildCommentPromptCard(currentPrompt, notice, masterFile) {
|
|
6353
|
+
return card(
|
|
6354
|
+
[
|
|
6355
|
+
...notice ? [md(notice)] : [],
|
|
6356
|
+
md("**\u270D\uFE0F \u8BC4\u8BBA\u63D0\u793A\u8BCD**"),
|
|
6357
|
+
note("\u8BC4\u8BBA @\u6211 \u65F6\u6211\u7684\u56FA\u5B9A\u4EBA\u8BBE\u4E0E\u56DE\u590D\u89C4\u5219\u2014\u2014\u4FDD\u5B58\u540E\u4F1A\u540C\u6B65\u5230\u6240\u6709\u6587\u6863\uFF08\u542B\u5386\u53F2\uFF09\uFF0C\u4E0B\u4E00\u6761\u8BC4\u8BBA\u751F\u6548\u3002"),
|
|
6358
|
+
md(
|
|
6359
|
+
[
|
|
6360
|
+
"**\u53EF\u7528\u53D8\u91CF**\uFF08\u540C\u6B65\u5230\u6BCF\u7BC7\u6587\u6863\u65F6\u81EA\u52A8\u66FF\u6362\u6210\u8BE5\u6587\u6863\u81EA\u5DF1\u7684\u503C\uFF09\uFF1A",
|
|
6361
|
+
"- `{docUrl}` \u6587\u6863\u94FE\u63A5",
|
|
6362
|
+
"- `{fileToken}` \u6587\u6863 token\uFF08\u94FE\u63A5\u91CC\u7C7B\u578B\u540E\u90A3\u6BB5\uFF09",
|
|
6363
|
+
"- `{fileType}` \u6587\u6863\u7C7B\u578B\uFF0C\u53D6\u503C\uFF1A",
|
|
6364
|
+
" - `doc`/`docx`\uFF08\u98DE\u4E66\u4E91\u6587\u6863\uFF09",
|
|
6365
|
+
" - `sheet`\uFF08\u98DE\u4E66\u8868\u683C\uFF09",
|
|
6366
|
+
" - `bitable`\uFF08\u591A\u7EF4\u8868\u683C\uFF09"
|
|
6367
|
+
].join("\n")
|
|
6368
|
+
),
|
|
6369
|
+
note("\u8BC4\u8BBA\u7684\u9009\u4E2D\u539F\u6587\u3001\u7528\u6237\u95EE\u9898\u6BCF\u8F6E\u4F1A\u81EA\u52A8\u7ED9\u6211\uFF0C\u65E0\u9700\u5199\u8FDB\u63D0\u793A\u8BCD\u3002"),
|
|
6370
|
+
form("comment_prompt", [
|
|
6371
|
+
input({
|
|
6372
|
+
name: "prompt",
|
|
6373
|
+
label: "\u63D0\u793A\u8BCD\u5185\u5BB9",
|
|
6374
|
+
value: currentPrompt,
|
|
6375
|
+
required: true,
|
|
6376
|
+
inputType: "multiline_text",
|
|
6377
|
+
rows: 12,
|
|
6378
|
+
width: "fill",
|
|
6379
|
+
maxLength: 1e3
|
|
6380
|
+
// Feishu input hard cap (range 1–1000); longer prompts → edit master file
|
|
6381
|
+
}),
|
|
6382
|
+
// 两个都是 form 提交按钮(普通 button 在 form 内不保证触发):保存读输入框内容落盘;
|
|
6383
|
+
// 重置忽略输入框、直接把内置默认写回 master 并同步(handler 端处理)。
|
|
6384
|
+
actions([
|
|
6385
|
+
submitButton("\u2705 \u4FDD\u5B58\u63D0\u793A\u8BCD", { a: DM.commentPromptSubmit }, "primary", "submit_prompt"),
|
|
6386
|
+
submitButton("\u21A9\uFE0F \u91CD\u7F6E\u4E3A\u9ED8\u8BA4", { a: DM.commentResetPrompt }, "default", "reset_prompt")
|
|
6387
|
+
])
|
|
6388
|
+
]),
|
|
6389
|
+
hr(),
|
|
6390
|
+
md("**\u{1F4E8} \u6BCF\u8F6E\u8BC4\u8BBA @\u6211\uFF0C\u6211\u4F1A\u6536\u5230\u4E0B\u9762\u6D88\u606F\uFF1A**"),
|
|
6391
|
+
md(
|
|
6392
|
+
[
|
|
6393
|
+
"\u6211\u5728\u98DE\u4E66\u4E91\u6587\u6863\u7684\u8BC4\u8BBA\u91CC @\u4E86\u4F60\u3002\u6587\u6863\u4FE1\u606F\uFF1A",
|
|
6394
|
+
"- \u94FE\u63A5\uFF1A{docUrl}",
|
|
6395
|
+
"- file_token\uFF1A{fileToken}",
|
|
6396
|
+
"- \u7C7B\u578B\uFF1A{fileType}",
|
|
6397
|
+
"- \u8BC4\u8BBA\u8303\u56F4\uFF1A\u884C\u5185\u8BC4\u8BBA\uFF08\u9488\u5BF9\u9009\u4E2D\u6587\u5B57\uFF09 / \u5168\u6587\u8BC4\u8BBA\uFF08\u9488\u5BF9\u6574\u7BC7\uFF09",
|
|
6398
|
+
"",
|
|
6399
|
+
// 空行结束列表,否则下一行被并进「评论范围」那个 bullet
|
|
6400
|
+
"\u7528\u6237\u9009\u4E2D\u7684\u539F\u6587\uFF1A\uFF08\u4EC5\u884C\u5185\u8BC4\u8BBA\u65F6\u9644\u4E0A\uFF09",
|
|
6401
|
+
"> \u2026\u2026\u88AB\u8BC4\u8BBA\u7684\u90A3\u6BB5\u6587\u5B57\u2026\u2026",
|
|
6402
|
+
"",
|
|
6403
|
+
// 空行结束引用,否则「用户的问题」被并进引用块
|
|
6404
|
+
"\u7528\u6237\u7684\u95EE\u9898\uFF1A\u2026\u2026\u8BC4\u8BBA\u6B63\u6587\u2026\u2026"
|
|
6405
|
+
].join("\n")
|
|
6406
|
+
),
|
|
6407
|
+
note(
|
|
6408
|
+
masterFile ? `\u63D0\u793A\u8BCD\u4E5F\u53EF\u76F4\u63A5\u7F16\u8F91 ${masterFile}\uFF08\u6539\u6587\u4EF6\u540E\u65B0\u5185\u5BB9\u5728\u6BCF\u7BC7\u6587\u6863\u7684\u4E0B\u4E00\u6761\u8BC4\u8BBA\u65F6\u751F\u6548\uFF09\u3002` : "\u63D0\u793A\u8BCD\u4E5F\u53EF\u76F4\u63A5\u7F16\u8F91 bot \u76EE\u5F55\u4E0B\u7684 comment-instructions.md\u3002"
|
|
6409
|
+
),
|
|
6410
|
+
actions([button("\u2B05\uFE0F \u8FD4\u56DE", { a: DM.commentSettings })])
|
|
6411
|
+
],
|
|
6412
|
+
{ header: { title: "\u270D\uFE0F \u7F16\u8F91\u63D0\u793A\u8BCD", template: "blue" }, widthMode: "fill" }
|
|
6413
|
+
);
|
|
6414
|
+
}
|
|
6200
6415
|
function buildWatchdogCustomCard(cfg) {
|
|
6201
6416
|
const cur = cfg.preferences?.runIdleTimeoutSeconds ?? 120;
|
|
6202
6417
|
return card(
|
|
@@ -6233,7 +6448,11 @@ function buildGroupSettingsCard(project) {
|
|
|
6233
6448
|
{ label: "\u5F00", value: "on" },
|
|
6234
6449
|
{ label: "\u5173", value: "off" }
|
|
6235
6450
|
]),
|
|
6236
|
-
note("\u5F00\u542F\u540E\uFF1A\u4E0A\u4E0B\u6587\u63A5\u8FD1\u4E0A\u9650\u65F6 Codex \u81EA\u52A8\u603B\u7ED3\u65E9\u524D\u5BF9\u8BDD\u3001\u91CA\u653E\u7A7A\u95F4\uFF08\u9ED8\u8BA4\u5F00\uFF09\u3002\u6539\u52A8\u4E0B\u4E00\u8F6E\u4F1A\u8BDD\u751F\u6548\u3002")
|
|
6451
|
+
note("\u5F00\u542F\u540E\uFF1A\u4E0A\u4E0B\u6587\u63A5\u8FD1\u4E0A\u9650\u65F6 Codex \u81EA\u52A8\u603B\u7ED3\u65E9\u524D\u5BF9\u8BDD\u3001\u91CA\u653E\u7A7A\u95F4\uFF08\u9ED8\u8BA4\u5F00\uFF09\u3002\u6539\u52A8\u4E0B\u4E00\u8F6E\u4F1A\u8BDD\u751F\u6548\u3002"),
|
|
6452
|
+
hr(),
|
|
6453
|
+
md("\u{1F916} \u9ED8\u8BA4\u6A21\u578B / \u63A8\u7406\u5F3A\u5EA6"),
|
|
6454
|
+
actions([button("\u8BBE\u7F6E\u9ED8\u8BA4\u6A21\u578B", { a: GS.modelDefault }, "primary")]),
|
|
6455
|
+
note(`\u5F53\u524D ${modelDefaultSummary(project)}\u3000\xB7\u3000\u65B0\u8BDD\u9898\u7684\u8D77\u59CB\u6A21\u578B / \u63A8\u7406\u5F3A\u5EA6\uFF08\u8BDD\u9898\u5185 \`/model\` \u53EF\u4E34\u65F6\u6539\uFF09\u3002`)
|
|
6237
6456
|
],
|
|
6238
6457
|
{ header: { title: "\u2699\uFE0F \u7FA4\u8BBE\u7F6E", template: "blue" } }
|
|
6239
6458
|
);
|
|
@@ -6348,6 +6567,81 @@ function buildPermissionCard(p) {
|
|
|
6348
6567
|
{ header: { title: "\u{1F510} \u6743\u9650", template: "blue" } }
|
|
6349
6568
|
);
|
|
6350
6569
|
}
|
|
6570
|
+
var EFFORT_ORDER = ["none", "minimal", "low", "medium", "high", "xhigh"];
|
|
6571
|
+
function modelDefaultSummary(p) {
|
|
6572
|
+
if (!p.defaultModel) return "\u540E\u7AEF\u9ED8\u8BA4\uFF08\u672A\u8BBE\uFF09";
|
|
6573
|
+
const eff = p.defaultEffort ? ` \xB7 \u5F3A\u5EA6 ${EFFORT_LABEL[p.defaultEffort]}` : "";
|
|
6574
|
+
return `${p.defaultModel}${eff}`;
|
|
6575
|
+
}
|
|
6576
|
+
function buildModelDefaultCard(p, models, ctx, notice) {
|
|
6577
|
+
const visible = models.filter((m) => !m.hidden);
|
|
6578
|
+
const explicit = p.defaultModel ? visible.find((m) => m.id === p.defaultModel) : void 0;
|
|
6579
|
+
const curModel = explicit ?? visible.find((m) => m.isDefault) ?? visible[0];
|
|
6580
|
+
const curEfforts = curModel?.supportedEfforts ?? [];
|
|
6581
|
+
const curEffort = explicit && p.defaultEffort && curEfforts.includes(p.defaultEffort) ? p.defaultEffort : curModel?.defaultEffort;
|
|
6582
|
+
const unionEfforts = EFFORT_ORDER.filter((e) => visible.some((m) => (m.supportedEfforts ?? []).includes(e)));
|
|
6583
|
+
const canPickModel = visible.length > 1;
|
|
6584
|
+
const canPickEffort = unionEfforts.length > 0;
|
|
6585
|
+
const submit = ctx === "dm" ? { a: DM.modelDefaultSubmit, n: p.name } : { a: GS.modelDefaultSubmit };
|
|
6586
|
+
const back = ctx === "dm" ? { a: DM.projectSettings, n: p.name } : { a: GS.settings };
|
|
6587
|
+
const head = [
|
|
6588
|
+
...notice ? [md(notice)] : [],
|
|
6589
|
+
md(`**\u{1F916} \u9ED8\u8BA4\u6A21\u578B / \u63A8\u7406\u5F3A\u5EA6** \xB7 ${p.name}`),
|
|
6590
|
+
note(
|
|
6591
|
+
"\u672C\u9879\u76EE**\u65B0\u8BDD\u9898**\u7684\u8D77\u59CB\u6A21\u578B\u4E0E\u63A8\u7406\u5F3A\u5EA6\u3002\u8FDB\u884C\u4E2D / \u5DF2\u6062\u590D\u7684\u4F1A\u8BDD\u4E0D\u53D7\u5F71\u54CD\uFF1B\u8BDD\u9898\u5185\u968F\u65F6\u53EF\u7528 `/model` \u4E34\u65F6\u6539\u3002\u672A\u8BBE\u65F6\u7528\u540E\u7AEF\u81EA\u5E26\u9ED8\u8BA4\u3002"
|
|
6592
|
+
)
|
|
6593
|
+
];
|
|
6594
|
+
if (!canPickModel && !canPickEffort) {
|
|
6595
|
+
return card(
|
|
6596
|
+
[
|
|
6597
|
+
...head,
|
|
6598
|
+
hr(),
|
|
6599
|
+
md(`\u5F53\u524D\u6A21\u578B\uFF1A**${curModel?.displayName ?? p.defaultModel ?? "\u540E\u7AEF\u9ED8\u8BA4"}**`),
|
|
6600
|
+
note("\u8BE5\u540E\u7AEF\u53EA\u6709\u4E00\u4E2A\u6A21\u578B\u4E14\u4E0D\u652F\u6301\u8C03\u8282\u63A8\u7406\u5F3A\u5EA6\uFF0C\u65E0\u9700\u8BBE\u7F6E\u9ED8\u8BA4\u3002"),
|
|
6601
|
+
actions([button("\u2B05\uFE0F \u8FD4\u56DE", back)])
|
|
6602
|
+
],
|
|
6603
|
+
{ header: { title: "\u{1F916} \u9ED8\u8BA4\u6A21\u578B", template: "blue" } }
|
|
6604
|
+
);
|
|
6605
|
+
}
|
|
6606
|
+
const formEls = [];
|
|
6607
|
+
if (canPickModel) {
|
|
6608
|
+
formEls.push(
|
|
6609
|
+
md("\u{1F916} **\u9ED8\u8BA4\u6A21\u578B**"),
|
|
6610
|
+
selectMenu({
|
|
6611
|
+
name: "model",
|
|
6612
|
+
placeholder: "\u9009\u62E9\u9ED8\u8BA4\u6A21\u578B",
|
|
6613
|
+
options: visible.map((m) => ({ label: m.displayName, value: m.id })),
|
|
6614
|
+
initial: curModel?.id
|
|
6615
|
+
})
|
|
6616
|
+
);
|
|
6617
|
+
}
|
|
6618
|
+
if (canPickEffort) {
|
|
6619
|
+
formEls.push(
|
|
6620
|
+
md("\u{1F9E0} **\u9ED8\u8BA4\u63A8\u7406\u5F3A\u5EA6**"),
|
|
6621
|
+
selectMenu({
|
|
6622
|
+
name: "effort",
|
|
6623
|
+
placeholder: "\u9009\u62E9\u9ED8\u8BA4\u63A8\u7406\u5F3A\u5EA6",
|
|
6624
|
+
options: unionEfforts.map((e) => ({ label: `\u5F3A\u5EA6\uFF1A${EFFORT_LABEL[e]}`, value: e })),
|
|
6625
|
+
initial: curEffort
|
|
6626
|
+
})
|
|
6627
|
+
);
|
|
6628
|
+
}
|
|
6629
|
+
formEls.push(actions([submitButton("\u2705 \u4FDD\u5B58\u9ED8\u8BA4", submit, "primary", "submit_model_default")]));
|
|
6630
|
+
return card(
|
|
6631
|
+
[
|
|
6632
|
+
...head,
|
|
6633
|
+
hr(),
|
|
6634
|
+
// single-model backend (effort-only form): name the locked model so the lone
|
|
6635
|
+
// effort dropdown isn't confusing.
|
|
6636
|
+
...canPickModel ? [] : [md(`\u9ED8\u8BA4\u6A21\u578B\uFF1A**${curModel?.displayName ?? "\u540E\u7AEF\u9ED8\u8BA4"}**\uFF08\u8BE5\u540E\u7AEF\u4EC5\u4E00\u4E2A\u6A21\u578B\uFF09`)],
|
|
6637
|
+
form("model_default", formEls),
|
|
6638
|
+
...canPickModel && !canPickEffort ? [note("\u8BE5\u540E\u7AEF\u4E0D\u8C03\u8282\u63A8\u7406\u5F3A\u5EA6\uFF08\u601D\u8003\u7531\u6A21\u578B\u81EA\u52A8\u8C03\u5EA6\uFF0C\u65E0 effort \u6863\uFF09\u3002")] : [],
|
|
6639
|
+
note("\u4FDD\u5B58\u53EA\u5F71\u54CD\u4E4B\u540E\u65B0\u5EFA\u7684\u8BDD\u9898\uFF0C\u4E0D\u4F1A\u6253\u65AD\u6B63\u5728\u8FDB\u884C\u7684\u4F1A\u8BDD\u3002"),
|
|
6640
|
+
actions([button("\u2B05\uFE0F \u8FD4\u56DE", back)])
|
|
6641
|
+
],
|
|
6642
|
+
{ header: { title: "\u{1F916} \u9ED8\u8BA4\u6A21\u578B", template: "blue" } }
|
|
6643
|
+
);
|
|
6644
|
+
}
|
|
6351
6645
|
function buildProjectSettingsCard(project, backendName, notice) {
|
|
6352
6646
|
const kind = project.kind ?? "multi";
|
|
6353
6647
|
const noMention = project.noMention ?? defaultNoMention(project);
|
|
@@ -6382,6 +6676,10 @@ function buildProjectSettingsCard(project, backendName, notice) {
|
|
|
6382
6676
|
]),
|
|
6383
6677
|
note("\u5F00\u542F\u540E\uFF1A\u4E0A\u4E0B\u6587\u63A5\u8FD1\u4E0A\u9650\u65F6 Codex \u81EA\u52A8\u603B\u7ED3\u65E9\u524D\u5BF9\u8BDD\u3001\u91CA\u653E\u7A7A\u95F4\uFF08\u9ED8\u8BA4\u5F00\uFF09\u3002\u6539\u52A8\u4E0B\u4E00\u8F6E\u4F1A\u8BDD\u751F\u6548\u3002"),
|
|
6384
6678
|
hr(),
|
|
6679
|
+
md("\u{1F916} \u9ED8\u8BA4\u6A21\u578B / \u63A8\u7406\u5F3A\u5EA6"),
|
|
6680
|
+
actions([button("\u8BBE\u7F6E\u9ED8\u8BA4\u6A21\u578B", { a: DM.modelDefault, n: project.name }, "primary")]),
|
|
6681
|
+
note(`\u5F53\u524D ${modelDefaultSummary(project)}\u3000\xB7\u3000\u65B0\u8BDD\u9898\u7684\u8D77\u59CB\u6A21\u578B / \u63A8\u7406\u5F3A\u5EA6\uFF08\u8BDD\u9898\u5185 \`/model\` \u53EF\u4E34\u65F6\u6539\uFF09\u3002`),
|
|
6682
|
+
hr(),
|
|
6385
6683
|
actions([button("\u{1F6E1} \u54CD\u5E94\u767D\u540D\u5355", { a: DM.allowlist, n: project.name }, "primary")]),
|
|
6386
6684
|
note("\u8BBE\u7F6E\u8C01\u80FD\u8BA9\u6211\u5728\u672C\u7FA4\u54CD\u5E94 / \u8DD1 codex\uFF08\u7A7A = \u6240\u6709\u4EBA\uFF09\u3002"),
|
|
6387
6685
|
hr(),
|
|
@@ -6547,6 +6845,12 @@ async function performSetAutoCompact(opts) {
|
|
|
6547
6845
|
await opts.evictLiveSessionsForChat(p.chatId);
|
|
6548
6846
|
return { ok: true, project: await freshOr(opts.projectName, { ...p, autoCompact: opts.on }) };
|
|
6549
6847
|
}
|
|
6848
|
+
async function performSetModelDefault(opts) {
|
|
6849
|
+
const p = await getProjectByName(opts.projectName);
|
|
6850
|
+
if (!p) return { ok: false, reason: `\u9879\u76EE\u300C${opts.projectName}\u300D\u4E0D\u5B58\u5728` };
|
|
6851
|
+
await updateProject(opts.projectName, { defaultModel: opts.model, defaultEffort: opts.effort });
|
|
6852
|
+
return { ok: true, project: await freshOr(opts.projectName, { ...p, defaultModel: opts.model, defaultEffort: opts.effort }) };
|
|
6853
|
+
}
|
|
6550
6854
|
function createAdminWriteExecutor(deps) {
|
|
6551
6855
|
return async (op) => {
|
|
6552
6856
|
const outcome = await runAdminWriteOp(op, deps);
|
|
@@ -10303,7 +10607,9 @@ function weaveSender(text, sender) {
|
|
|
10303
10607
|
|
|
10304
10608
|
// src/bot/comments.ts
|
|
10305
10609
|
init_logger();
|
|
10306
|
-
|
|
10610
|
+
import { mkdir as mkdir14, readdir as readdir4, readFile as readFile12, writeFile as writeFile11 } from "fs/promises";
|
|
10611
|
+
import { dirname as dirname12, join as join19 } from "path";
|
|
10612
|
+
var SUPPORTED_FILE_TYPES = /* @__PURE__ */ new Set(["doc", "docx", "sheet", "bitable"]);
|
|
10307
10613
|
var REPLY_MAX_CHARS = 2e3;
|
|
10308
10614
|
function apiErrCode(err) {
|
|
10309
10615
|
return err?.response?.data?.code;
|
|
@@ -10398,10 +10704,80 @@ var DOC_HOSTS = {
|
|
|
10398
10704
|
feishu: "feishu.cn",
|
|
10399
10705
|
lark: "larksuite.com"
|
|
10400
10706
|
};
|
|
10707
|
+
var DOC_URL_PATH = {
|
|
10708
|
+
doc: "docs",
|
|
10709
|
+
docx: "docx",
|
|
10710
|
+
sheet: "sheets",
|
|
10711
|
+
bitable: "base"
|
|
10712
|
+
};
|
|
10713
|
+
function buildDocUrl(tenant, fileType, fileToken) {
|
|
10714
|
+
const seg = DOC_URL_PATH[fileType] ?? fileType;
|
|
10715
|
+
return `https://${DOC_HOSTS[tenant]}/${seg}/${fileToken}`;
|
|
10716
|
+
}
|
|
10717
|
+
var DEFAULT_COMMENT_INSTRUCTIONS = `# \u98DE\u4E66\u4E91\u6587\u6863\u8BC4\u8BBA\u52A9\u624B
|
|
10718
|
+
|
|
10719
|
+
\u4F60\u88AB @ \u5728\u4E00\u7BC7\u98DE\u4E66\u4E91\u6587\u6863\uFF08{docUrl}\uFF0C\u7C7B\u578B {fileType}\uFF0Cfile_token\uFF1A{fileToken}\uFF09\u7684\u8BC4\u8BBA\u91CC\u3002\u7CFB\u7EDF\u4F1A\u628A\u4F60\u8FD9\u4E00\u8F6E\u7684\u6700\u7EC8\u56DE\u590D\u81EA\u52A8\u8D34\u56DE\u8FD9\u6761\u8BC4\u8BBA\u3002\u6BCF\u8F6E\u8FD8\u4F1A\u7ED9\u4F60\u8BC4\u8BBA\u8303\u56F4\u548C\uFF08\u884C\u5185\u8BC4\u8BBA\u65F6\uFF09\u9009\u4E2D\u7684\u539F\u6587\u3002
|
|
10720
|
+
|
|
10721
|
+
## \u600E\u4E48\u505A
|
|
10722
|
+
- \u9700\u8981\u770B\u6B63\u6587\uFF0C\u6216\u7528\u6237\u8981\u6C42"\u5E2E\u6211\u6539 / \u4F18\u5316 / \u91CD\u5199 / \u7EC6\u5316\u8FD9\u6BB5"\u65F6\uFF0C\u7528 lark-cli \u8BFB / \u6539\u8FD9\u7BC7\u6587\u6863\uFF08{fileToken}\uFF09\u3002
|
|
10723
|
+
- \u6539\u6587\u6863\u65F6\u7EDD\u4E0D\u8981\u5220\u9664\u6216\u6574\u6BB5\u66FF\u6362"\u88AB\u8BC4\u8BBA\u7684\u539F\u6587"\uFF08\u672C\u8F6E\u7ED9\u4F60\u7684\u9009\u4E2D\u539F\u6587\uFF09\u2014\u2014\u98DE\u4E66\u8BC4\u8BBA\u951A\u5B9A\u5728\u8FD9\u6BB5\u6587\u5B57\u4E0A\uFF0C\u5220\u4E86\u5B83\u8BC4\u8BBA\u4F1A\u53D8\u6210"\u539F\u6587\u5DF2\u88AB\u5220\u9664"\u3001\u79FB\u8FDB\u5386\u53F2\u8BC4\u8BBA\uFF0C\u6B63\u6587\u5C31\u770B\u4E0D\u5230\u4E86\u3002\u8981\u4FDD\u7559\u8FD9\u6BB5\u539F\u6587\uFF0C\u5728\u5B83\u4E4B\u540E\u6216\u5468\u56F4\u589E\u6539\uFF0C\u53EA\u52A8\u8FD9\u4E00\u5904\u3002
|
|
10724
|
+
- \u6539\u5B8C\u53EA\u56DE\u4E00\u53E5\u7B80\u77ED\u8BF4\u660E\uFF1B\u7528\u6237\u53EA\u662F\u63D0\u95EE\u5C31\u76F4\u63A5\u7B54\uFF0C\u4E0D\u6539\u4EFB\u4F55\u4E1C\u897F\u3002
|
|
10725
|
+
|
|
10726
|
+
## \u5FC5\u987B\u9075\u5B88
|
|
10727
|
+
1. \u4E0D\u8981\u81EA\u5DF1\u53D1\u8868 / \u56DE\u590D / \u89E3\u51B3 / \u5220\u9664\u4EFB\u4F55\u98DE\u4E66\u8BC4\u8BBA\u2014\u2014\u7CFB\u7EDF\u4F1A\u81EA\u52A8\u628A\u4F60\u7684\u6700\u7EC8\u56DE\u590D\u8D34\u4E0A\u53BB\u3002
|
|
10728
|
+
2. \u53EA\u8F93\u51FA\u6700\u7EC8\u7B54\u6848\u672C\u8EAB\uFF0C\u4E0D\u8981\u590D\u8FF0\u5206\u6790\u8FC7\u7A0B\u6216"\u6211\u73B0\u5728\u53BB\u2026"\u3002
|
|
10729
|
+
3. \u5168\u7A0B\u7EAF\u6587\u672C\uFF1A\u4E0D\u8981\u4EFB\u4F55 markdown \u6807\u8BB0\uFF08** __ # - * > \u53CD\u5F15\u53F7 \u4E4B\u7C7B\uFF09\u3001\u4E0D\u8981\u4EE3\u7801\u5757\u3001\u4E0D\u8981\u8868\u683C\u2014\u2014\u8BC4\u8BBA\u6846\u4E0D\u6E32\u67D3\uFF0C\u4F1A\u539F\u6837\u663E\u793A\u8FD9\u4E9B\u7B26\u53F7\u3002\u8BED\u6C14\u7B80\u6D01\u76F4\u63A5\u3002
|
|
10730
|
+
`;
|
|
10731
|
+
function commentSessionKey(fileToken, commentId) {
|
|
10732
|
+
return `doc:${fileToken}:${commentId}`;
|
|
10733
|
+
}
|
|
10734
|
+
function commentCwd(projectsRoot, fileType, fileToken) {
|
|
10735
|
+
return join19(projectsRoot, `comment-${fileType}-${fileToken}`);
|
|
10736
|
+
}
|
|
10737
|
+
async function loadCommentInstructions(masterFile) {
|
|
10738
|
+
try {
|
|
10739
|
+
const existing = await readFile12(masterFile, "utf8");
|
|
10740
|
+
return existing.trim() ? existing : DEFAULT_COMMENT_INSTRUCTIONS;
|
|
10741
|
+
} catch {
|
|
10742
|
+
}
|
|
10743
|
+
await mkdir14(dirname12(masterFile), { recursive: true }).catch(() => void 0);
|
|
10744
|
+
await writeFile11(masterFile, DEFAULT_COMMENT_INSTRUCTIONS, "utf8").catch(() => void 0);
|
|
10745
|
+
return DEFAULT_COMMENT_INSTRUCTIONS;
|
|
10746
|
+
}
|
|
10747
|
+
async function syncCommentInstructions(cwd, instructions) {
|
|
10748
|
+
await mkdir14(cwd, { recursive: true });
|
|
10749
|
+
await Promise.all([
|
|
10750
|
+
writeFile11(join19(cwd, "AGENTS.md"), instructions, "utf8"),
|
|
10751
|
+
writeFile11(join19(cwd, "CLAUDE.md"), instructions, "utf8")
|
|
10752
|
+
]);
|
|
10753
|
+
}
|
|
10754
|
+
async function saveCommentInstructions(masterFile, content) {
|
|
10755
|
+
await mkdir14(dirname12(masterFile), { recursive: true });
|
|
10756
|
+
await writeFile11(masterFile, content, "utf8");
|
|
10757
|
+
}
|
|
10758
|
+
function renderCommentInstructions(template, tenant, fileType, fileToken) {
|
|
10759
|
+
const docUrl = buildDocUrl(tenant, fileType, fileToken);
|
|
10760
|
+
return template.replace(/\{fileType\}/g, fileType).replace(/\{fileToken\}/g, fileToken).replace(/\{docUrl\}/g, docUrl);
|
|
10761
|
+
}
|
|
10762
|
+
async function syncAllCommentInstructions(projectsRoot, rawTemplate, tenant) {
|
|
10763
|
+
const entries = await readdir4(projectsRoot, { withFileTypes: true }).catch(() => []);
|
|
10764
|
+
let synced = 0;
|
|
10765
|
+
for (const e of entries) {
|
|
10766
|
+
if (!e.isDirectory() || !e.name.startsWith("comment-")) continue;
|
|
10767
|
+
const m = /^comment-([a-z]+)-(.+)$/.exec(e.name);
|
|
10768
|
+
const fileType = m?.[1];
|
|
10769
|
+
const fileToken = m?.[2];
|
|
10770
|
+
if (!fileType || !fileToken) continue;
|
|
10771
|
+
const rendered = renderCommentInstructions(rawTemplate, tenant, fileType, fileToken);
|
|
10772
|
+
await syncCommentInstructions(join19(projectsRoot, e.name), rendered).catch(() => void 0);
|
|
10773
|
+
synced++;
|
|
10774
|
+
}
|
|
10775
|
+
return synced;
|
|
10776
|
+
}
|
|
10401
10777
|
function buildCommentPrompt(target, ctx, tenant) {
|
|
10402
|
-
const docUrl =
|
|
10778
|
+
const docUrl = buildDocUrl(tenant, target.fileType, target.fileToken);
|
|
10403
10779
|
const parts = [];
|
|
10404
|
-
parts.push("\u6211\u5728\u98DE\u4E66\u4E91\u6587\u6863\u7684\u8BC4\u8BBA\u91CC
|
|
10780
|
+
parts.push("\u6211\u5728\u98DE\u4E66\u4E91\u6587\u6863\u7684\u8BC4\u8BBA\u91CC @\u4E86\u4F60\u3002\u6587\u6863\u4FE1\u606F\uFF1A");
|
|
10405
10781
|
parts.push(`- \u94FE\u63A5\uFF1A${docUrl}`);
|
|
10406
10782
|
parts.push(`- file_token\uFF1A${target.fileToken}`);
|
|
10407
10783
|
parts.push(`- \u7C7B\u578B\uFF1A${target.fileType}`);
|
|
@@ -10413,20 +10789,6 @@ function buildCommentPrompt(target, ctx, tenant) {
|
|
|
10413
10789
|
}
|
|
10414
10790
|
parts.push("");
|
|
10415
10791
|
parts.push(`\u7528\u6237\u7684\u95EE\u9898\uFF1A${ctx.question}`);
|
|
10416
|
-
parts.push("");
|
|
10417
|
-
parts.push(
|
|
10418
|
-
`\u5982\u679C\u56DE\u7B54\u9700\u8981\u6587\u6863\u6B63\u6587\u5185\u5BB9\uFF0C\u53EF\u7528 lark-cli \u53EA\u8BFB\u5730\u83B7\u53D6\uFF08\u4EC5\u7528\u4E8E\u8BFB\u53D6\uFF0C\u4E0D\u8981\u7528\u5B83\u5199\u4EFB\u4F55\u4E1C\u897F\uFF09\uFF1A
|
|
10419
|
-
lark-cli docs +fetch --doc ${target.fileToken} --api-version v2`
|
|
10420
|
-
);
|
|
10421
|
-
parts.push("");
|
|
10422
|
-
parts.push("\u3010\u975E\u5E38\u91CD\u8981\uFF0C\u52A1\u5FC5\u9075\u5B88\u3011");
|
|
10423
|
-
parts.push(
|
|
10424
|
-
"1. \u4E0D\u8981\u81EA\u5DF1\u53BB\u53D1\u8868 / \u56DE\u590D / \u4FEE\u6539\u4EFB\u4F55\u98DE\u4E66\u8BC4\u8BBA\u6216\u6587\u6863\uFF08\u4E5F\u4E0D\u8981\u7528 lark-cli \u6216\u4EFB\u4F55\u5DE5\u5177\u53BB\u53D1\u8BC4\u8BBA\uFF09\u2014\u2014\u7CFB\u7EDF\u4F1A\u81EA\u52A8\u628A\u4F60\u4E0B\u9762\u7ED9\u51FA\u7684\u6700\u7EC8\u56DE\u590D\u53D1\u5230\u8FD9\u6761\u8BC4\u8BBA\u91CC\uFF0C\u4F60\u53EA\u7BA1\u628A\u7B54\u6848\u5199\u51FA\u6765\u3002"
|
|
10425
|
-
);
|
|
10426
|
-
parts.push("2. \u53EA\u8F93\u51FA\u8981\u53D1\u7ED9\u7528\u6237\u7684\u300C\u6700\u7EC8\u7B54\u6848\u300D\u672C\u8EAB\uFF0C\u4E0D\u8981\u590D\u8FF0\u5206\u6790\u8FC7\u7A0B\u3001\u6B65\u9AA4\u3001\u6216\u300C\u6211\u73B0\u5728\u53BB\u2026\u300D\u8FD9\u7C7B\u8BF4\u660E\u3002");
|
|
10427
|
-
parts.push(
|
|
10428
|
-
"3. \u7528\u7EAF\u6587\u672C\uFF0C\u4E0D\u8981\u7528 markdown \u6807\u8BB0\uFF08\u4E0D\u8981 ** __ # - * > ` \u4E4B\u7C7B\uFF09\uFF0C\u4E0D\u8981\u4EE3\u7801\u5757\uFF1B\u8BC4\u8BBA\u6846\u4E0D\u6E32\u67D3 markdown\uFF0C\u4F1A\u539F\u6837\u663E\u793A\u8FD9\u4E9B\u7B26\u53F7\u3002\u56DE\u7B54\u7B80\u6D01\u76F4\u63A5\u3002"
|
|
10429
|
-
);
|
|
10430
10792
|
return parts.join("\n");
|
|
10431
10793
|
}
|
|
10432
10794
|
function stripMarkdown(s) {
|
|
@@ -10686,6 +11048,17 @@ function selectValue(formValue, name) {
|
|
|
10686
11048
|
function asTier(v) {
|
|
10687
11049
|
return v === "qa" || v === "write" || v === "full" ? v : void 0;
|
|
10688
11050
|
}
|
|
11051
|
+
var REASONING_EFFORTS = ["none", "minimal", "low", "medium", "high", "xhigh"];
|
|
11052
|
+
function asEffort(v) {
|
|
11053
|
+
return v !== void 0 && REASONING_EFFORTS.includes(v) ? v : void 0;
|
|
11054
|
+
}
|
|
11055
|
+
function pickDefault(models, prefer) {
|
|
11056
|
+
const preferred = prefer?.model ? models.find((m) => m.id === prefer.model && !m.hidden) : void 0;
|
|
11057
|
+
const def = preferred ?? models.find((m) => m.isDefault && !m.hidden) ?? models.find((m) => !m.hidden) ?? models[0];
|
|
11058
|
+
const supported = def?.supportedEfforts ?? [];
|
|
11059
|
+
const effort = preferred && prefer?.effort && supported.includes(prefer.effort) ? prefer.effort : def?.defaultEffort ?? "medium";
|
|
11060
|
+
return { model: def?.id ?? "gpt-5.5", effort };
|
|
11061
|
+
}
|
|
10689
11062
|
function backendOptionsFor(mode) {
|
|
10690
11063
|
const opts = visibleCatalog().filter((e) => !e.supportedModes || e.supportedModes.includes(mode)).map((e) => {
|
|
10691
11064
|
const installed = e.id === DEFAULT_BACKEND_ID || isBackendEntryInstalled(e);
|
|
@@ -10795,6 +11168,7 @@ function createOrchestrator(channel, cfg, fallbackCwd, cliBridge) {
|
|
|
10795
11168
|
}
|
|
10796
11169
|
const active = /* @__PURE__ */ new Map();
|
|
10797
11170
|
const docLocks = /* @__PURE__ */ new Map();
|
|
11171
|
+
const commentInstrUsed = /* @__PURE__ */ new Map();
|
|
10798
11172
|
const sema = new Semaphore(getMaxConcurrentRuns(cfg));
|
|
10799
11173
|
const currentIdleMs = () => getRunIdleTimeoutMs(cfg) ?? 0;
|
|
10800
11174
|
const resumePending = /* @__PURE__ */ new Map();
|
|
@@ -10806,10 +11180,6 @@ function createOrchestrator(channel, cfg, fallbackCwd, cliBridge) {
|
|
|
10806
11180
|
const lastUsage = /* @__PURE__ */ new Map();
|
|
10807
11181
|
const seenInbound = new RecentIdCache();
|
|
10808
11182
|
const listModels = (be = backend) => be.listModels();
|
|
10809
|
-
function pickDefault(models) {
|
|
10810
|
-
const def = models.find((m) => m.isDefault && !m.hidden) ?? models.find((m) => !m.hidden) ?? models[0];
|
|
10811
|
-
return { model: def?.id ?? "gpt-5.5", effort: def?.defaultEffort ?? "medium" };
|
|
10812
|
-
}
|
|
10813
11183
|
async function addReaction(messageId, emoji) {
|
|
10814
11184
|
try {
|
|
10815
11185
|
const r = await channel.rawClient.im.v1.messageReaction.create({
|
|
@@ -11272,7 +11642,10 @@ function createOrchestrator(channel, cfg, fallbackCwd, cliBridge) {
|
|
|
11272
11642
|
const tIntake = Date.now();
|
|
11273
11643
|
let tResolveDone = tIntake;
|
|
11274
11644
|
const threadP = (async () => {
|
|
11275
|
-
const { model: model2, effort: effort2 } = pickDefault(await listModels(be)
|
|
11645
|
+
const { model: model2, effort: effort2 } = pickDefault(await listModels(be), {
|
|
11646
|
+
model: project?.defaultModel,
|
|
11647
|
+
effort: project?.defaultEffort
|
|
11648
|
+
});
|
|
11276
11649
|
const thread2 = await be.startThread({ cwd, model: model2, effort: effort2, mode: perm.mode, network: perm.network, autoCompact: perm.autoCompact });
|
|
11277
11650
|
tResolveDone = Date.now();
|
|
11278
11651
|
return { thread: thread2, model: model2, effort: effort2 };
|
|
@@ -11360,7 +11733,7 @@ function createOrchestrator(channel, cfg, fallbackCwd, cliBridge) {
|
|
|
11360
11733
|
const [rec, project] = await Promise.all([getSession(sessionKey), getProjectByChatId(msg.chatId)]);
|
|
11361
11734
|
const be = backendFor(rec?.backend ?? project?.backend);
|
|
11362
11735
|
const models = await listModels(be);
|
|
11363
|
-
const def = pickDefault(models);
|
|
11736
|
+
const def = pickDefault(models, { model: project?.defaultModel, effort: project?.defaultEffort });
|
|
11364
11737
|
const recModel = rec?.model && models.some((m) => m.id === rec.model) ? rec.model : void 0;
|
|
11365
11738
|
const state = {
|
|
11366
11739
|
chatId: msg.chatId,
|
|
@@ -11644,10 +12017,13 @@ function createOrchestrator(channel, cfg, fallbackCwd, cliBridge) {
|
|
|
11644
12017
|
if (opts?.render !== false) void patch(evt, renderSettings);
|
|
11645
12018
|
}
|
|
11646
12019
|
let cliHookStatuses;
|
|
11647
|
-
|
|
12020
|
+
function renderSettings() {
|
|
12021
|
+
return buildSettingsCard(cfg);
|
|
12022
|
+
}
|
|
12023
|
+
async function renderCoffeeSettings(refreshHooks = false) {
|
|
11648
12024
|
if (refreshHooks || !cliHookStatuses) cliHookStatuses = await inspectCliBridgeHooks();
|
|
11649
12025
|
const cliPrefs = getCliBridgePreferences(cfg);
|
|
11650
|
-
const
|
|
12026
|
+
const section = cliBridgeSettingsSection({
|
|
11651
12027
|
enabled: cliPrefs.enabled,
|
|
11652
12028
|
statuses: cliHookStatuses,
|
|
11653
12029
|
canEnable: canEnableCliBridge(cfg),
|
|
@@ -11655,7 +12031,25 @@ function createOrchestrator(channel, cfg, fallbackCwd, cliBridge) {
|
|
|
11655
12031
|
agents: cliPrefs.agents,
|
|
11656
12032
|
keepAwake: cliPrefs.keepAwake.enabled
|
|
11657
12033
|
});
|
|
11658
|
-
return
|
|
12034
|
+
return buildCoffeeSettingsCard(section);
|
|
12035
|
+
}
|
|
12036
|
+
function commentBackendOptions() {
|
|
12037
|
+
return visibleCatalog().filter((e) => e.id === DEFAULT_BACKEND_ID || isBackendEntryInstalled(e)).map((e) => ({ id: e.id, label: e.displayName }));
|
|
12038
|
+
}
|
|
12039
|
+
async function renderCommentSettings(notice) {
|
|
12040
|
+
const comments = getCommentsConfig(cfg);
|
|
12041
|
+
const models = await listModels(backendFor(comments.backend)).catch(() => []);
|
|
12042
|
+
return buildCommentSettingsCard(cfg, commentBackendOptions(), models, notice);
|
|
12043
|
+
}
|
|
12044
|
+
function applyCommentsPref(evt, mut) {
|
|
12045
|
+
if (!dmAdmin(evt.operator?.openId)) return;
|
|
12046
|
+
const prefs = { ...cfg.preferences ?? {} };
|
|
12047
|
+
const comments = { ...prefs.comments ?? {} };
|
|
12048
|
+
mut(comments);
|
|
12049
|
+
prefs.comments = comments;
|
|
12050
|
+
cfg.preferences = prefs;
|
|
12051
|
+
void saveConfig(cfg).catch((err) => log.fail("console", err, { phase: "save-config" }));
|
|
12052
|
+
void patch(evt, () => renderCommentSettings());
|
|
11659
12053
|
}
|
|
11660
12054
|
const freshMenu = (evt) => {
|
|
11661
12055
|
patch(evt, buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() }));
|
|
@@ -11700,7 +12094,7 @@ function createOrchestrator(channel, cfg, fallbackCwd, cliBridge) {
|
|
|
11700
12094
|
}
|
|
11701
12095
|
})();
|
|
11702
12096
|
};
|
|
11703
|
-
const renderProjectList = async () => {
|
|
12097
|
+
const renderProjectList = async (page = 0) => {
|
|
11704
12098
|
const [projects, sessions2] = await Promise.all([listProjects(), listSessions()]);
|
|
11705
12099
|
const byChat = /* @__PURE__ */ new Map();
|
|
11706
12100
|
for (const s of sessions2) {
|
|
@@ -11708,7 +12102,7 @@ function createOrchestrator(channel, cfg, fallbackCwd, cliBridge) {
|
|
|
11708
12102
|
if (arr) arr.push(s);
|
|
11709
12103
|
else byChat.set(s.chatId, [s]);
|
|
11710
12104
|
}
|
|
11711
|
-
return buildProjectListCard(projects, byChat);
|
|
12105
|
+
return buildProjectListCard(projects, byChat, page);
|
|
11712
12106
|
};
|
|
11713
12107
|
const buildDoctorInfo = async () => {
|
|
11714
12108
|
const codexProbe = await backend.doctor({ force: true });
|
|
@@ -11799,11 +12193,14 @@ function createOrchestrator(channel, cfg, fallbackCwd, cliBridge) {
|
|
|
11799
12193
|
(e) => log.fail("console", e, { phase: "join-group-result" })
|
|
11800
12194
|
);
|
|
11801
12195
|
})();
|
|
11802
|
-
}).on(DM.projects, ({ evt }) => {
|
|
12196
|
+
}).on(DM.projects, ({ evt, value }) => {
|
|
11803
12197
|
if (!dmAdmin(evt.operator?.openId)) return;
|
|
11804
|
-
|
|
12198
|
+
const page = typeof value.p === "number" ? value.p : Number(value.p) || 0;
|
|
12199
|
+
patch(evt, () => renderProjectList(page));
|
|
11805
12200
|
}).on(DM.settings, async ({ evt }) => {
|
|
11806
|
-
if (dmAdmin(evt.operator?.openId)) await patch(evt,
|
|
12201
|
+
if (dmAdmin(evt.operator?.openId)) await patch(evt, renderSettings);
|
|
12202
|
+
}).on(DM.coffeeSettings, async ({ evt }) => {
|
|
12203
|
+
if (dmAdmin(evt.operator?.openId)) await patch(evt, () => renderCoffeeSettings(true));
|
|
11807
12204
|
}).on(CLI.toggleEnabled, async ({ evt, value }) => {
|
|
11808
12205
|
if (!dmAdmin(evt.operator?.openId)) return;
|
|
11809
12206
|
const enabled = value.v === "on";
|
|
@@ -11823,7 +12220,7 @@ function createOrchestrator(channel, cfg, fallbackCwd, cliBridge) {
|
|
|
11823
12220
|
} catch (err) {
|
|
11824
12221
|
log.fail("cli-bridge", err, { phase: enabled ? "enable" : "disable" });
|
|
11825
12222
|
}
|
|
11826
|
-
void patch(evt,
|
|
12223
|
+
void patch(evt, renderCoffeeSettings);
|
|
11827
12224
|
}).on(CLI.repairHooks, async ({ evt }) => {
|
|
11828
12225
|
if (!dmAdmin(evt.operator?.openId)) return;
|
|
11829
12226
|
try {
|
|
@@ -11834,13 +12231,14 @@ function createOrchestrator(channel, cfg, fallbackCwd, cliBridge) {
|
|
|
11834
12231
|
} catch (err) {
|
|
11835
12232
|
log.fail("cli-bridge", err, { phase: "repair-hooks" });
|
|
11836
12233
|
}
|
|
11837
|
-
await patch(evt, () =>
|
|
12234
|
+
await patch(evt, () => renderCoffeeSettings(true));
|
|
11838
12235
|
}).on(CLI.setNotifyScope, ({ evt, value }) => {
|
|
11839
12236
|
if (!dmAdmin(evt.operator?.openId)) return;
|
|
11840
12237
|
const scope = value.v === "bound_projects" || value.v === "none" ? value.v : "all";
|
|
11841
12238
|
applyPref(evt, (p) => {
|
|
11842
12239
|
p.cliBridge = { ...p.cliBridge ?? {}, notifyScope: scope };
|
|
11843
|
-
});
|
|
12240
|
+
}, { render: false });
|
|
12241
|
+
void patch(evt, renderCoffeeSettings);
|
|
11844
12242
|
}).on(CLI.toggleAgent, ({ evt, value }) => {
|
|
11845
12243
|
if (!dmAdmin(evt.operator?.openId)) return;
|
|
11846
12244
|
const agent = value.agent === "codex" ? "codex" : "claude";
|
|
@@ -11848,14 +12246,16 @@ function createOrchestrator(channel, cfg, fallbackCwd, cliBridge) {
|
|
|
11848
12246
|
applyPref(evt, (p) => {
|
|
11849
12247
|
const cur = p.cliBridge ?? {};
|
|
11850
12248
|
p.cliBridge = { ...cur, agents: { ...cur.agents ?? {}, [agent]: on } };
|
|
11851
|
-
});
|
|
12249
|
+
}, { render: false });
|
|
12250
|
+
void patch(evt, renderCoffeeSettings);
|
|
11852
12251
|
}).on(CLI.toggleKeepAwake, ({ evt, value }) => {
|
|
11853
12252
|
if (!dmAdmin(evt.operator?.openId)) return;
|
|
11854
12253
|
const on = value.v === "on";
|
|
11855
12254
|
applyPref(evt, (p) => {
|
|
11856
12255
|
const cur = p.cliBridge ?? {};
|
|
11857
12256
|
p.cliBridge = { ...cur, keepAwake: { ...cur.keepAwake ?? {}, enabled: on } };
|
|
11858
|
-
});
|
|
12257
|
+
}, { render: false });
|
|
12258
|
+
void patch(evt, renderCoffeeSettings);
|
|
11859
12259
|
}).on(DM.doctor, async ({ evt }) => {
|
|
11860
12260
|
if (!dmAdmin(evt.operator?.openId)) return;
|
|
11861
12261
|
await sendManagedCard(channel, evt.chatId, buildDoctorCard(await buildDoctorInfo()), evt.messageId).catch(
|
|
@@ -11997,6 +12397,78 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
11997
12397
|
}).on(DM.setConcurrency, ({ evt, value }) => {
|
|
11998
12398
|
const n = Number(value.v);
|
|
11999
12399
|
if (Number.isFinite(n)) applyPref(evt, (p) => p.maxConcurrentRuns = n);
|
|
12400
|
+
}).on(DM.commentSettings, ({ evt }) => {
|
|
12401
|
+
if (!dmAdmin(evt.operator?.openId)) return;
|
|
12402
|
+
void patch(evt, () => renderCommentSettings());
|
|
12403
|
+
}).on(DM.commentSetBackend, ({ evt, value }) => {
|
|
12404
|
+
const v = typeof value.v === "string" ? value.v : void 0;
|
|
12405
|
+
applyCommentsPref(evt, (c) => {
|
|
12406
|
+
c.backend = v && backendIds().includes(v) ? v : void 0;
|
|
12407
|
+
c.model = void 0;
|
|
12408
|
+
c.effort = void 0;
|
|
12409
|
+
});
|
|
12410
|
+
}).on(DM.commentSubmit, ({ evt, formValue }) => {
|
|
12411
|
+
if (!dmAdmin(evt.operator?.openId)) return;
|
|
12412
|
+
const modelId = selectValue(formValue, "model");
|
|
12413
|
+
const effort = asEffort(selectValue(formValue, "effort"));
|
|
12414
|
+
applyCommentsPref(evt, (c) => {
|
|
12415
|
+
if (modelId) c.model = modelId;
|
|
12416
|
+
if (effort) c.effort = effort;
|
|
12417
|
+
});
|
|
12418
|
+
}).on(DM.commentEditPrompt, ({ evt }) => {
|
|
12419
|
+
if (!dmAdmin(evt.operator?.openId)) return;
|
|
12420
|
+
void patch(
|
|
12421
|
+
evt,
|
|
12422
|
+
async () => buildCommentPromptCard(
|
|
12423
|
+
await loadCommentInstructions(paths.commentInstructionsFile),
|
|
12424
|
+
void 0,
|
|
12425
|
+
paths.commentInstructionsFile
|
|
12426
|
+
)
|
|
12427
|
+
);
|
|
12428
|
+
}).on(DM.commentPromptSubmit, ({ evt, formValue }) => {
|
|
12429
|
+
if (!dmAdmin(evt.operator?.openId)) return;
|
|
12430
|
+
const content = typeof formValue?.prompt === "string" ? formValue.prompt : "";
|
|
12431
|
+
void (async () => {
|
|
12432
|
+
if (!content.trim()) {
|
|
12433
|
+
const cur = await loadCommentInstructions(paths.commentInstructionsFile);
|
|
12434
|
+
await patch(evt, buildCommentPromptCard(cur, "\u26A0\uFE0F \u63D0\u793A\u8BCD\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u672A\u4FDD\u5B58\u3002", paths.commentInstructionsFile));
|
|
12435
|
+
return;
|
|
12436
|
+
}
|
|
12437
|
+
await saveCommentInstructions(paths.commentInstructionsFile, content).catch(
|
|
12438
|
+
(err) => log.fail("console", err, { phase: "save-comment-prompt" })
|
|
12439
|
+
);
|
|
12440
|
+
const n = await syncAllCommentInstructions(paths.commentsRootDir, content, cfg.accounts.app.tenant).catch(
|
|
12441
|
+
() => 0
|
|
12442
|
+
);
|
|
12443
|
+
await patch(
|
|
12444
|
+
evt,
|
|
12445
|
+
() => buildCommentPromptCard(
|
|
12446
|
+
content,
|
|
12447
|
+
`\u2705 \u63D0\u793A\u8BCD\u5DF2\u4FDD\u5B58\uFF0C\u5DF2\u540C\u6B65\u5230 ${n} \u4E2A\u6587\u6863\uFF08\u542B\u5386\u53F2\uFF09\uFF0C\u4E0B\u4E00\u6761\u8BC4\u8BBA\u751F\u6548\u3002`,
|
|
12448
|
+
paths.commentInstructionsFile
|
|
12449
|
+
)
|
|
12450
|
+
);
|
|
12451
|
+
})();
|
|
12452
|
+
}).on(DM.commentResetPrompt, ({ evt }) => {
|
|
12453
|
+
if (!dmAdmin(evt.operator?.openId)) return;
|
|
12454
|
+
void (async () => {
|
|
12455
|
+
await saveCommentInstructions(paths.commentInstructionsFile, DEFAULT_COMMENT_INSTRUCTIONS).catch(
|
|
12456
|
+
(err) => log.fail("console", err, { phase: "reset-comment-prompt" })
|
|
12457
|
+
);
|
|
12458
|
+
const n = await syncAllCommentInstructions(
|
|
12459
|
+
paths.commentsRootDir,
|
|
12460
|
+
DEFAULT_COMMENT_INSTRUCTIONS,
|
|
12461
|
+
cfg.accounts.app.tenant
|
|
12462
|
+
).catch(() => 0);
|
|
12463
|
+
await patch(
|
|
12464
|
+
evt,
|
|
12465
|
+
() => buildCommentPromptCard(
|
|
12466
|
+
DEFAULT_COMMENT_INSTRUCTIONS,
|
|
12467
|
+
`\u21A9\uFE0F \u5DF2\u91CD\u7F6E\u4E3A\u9ED8\u8BA4\u63D0\u793A\u8BCD\uFF0C\u5DF2\u540C\u6B65\u5230 ${n} \u4E2A\u6587\u6863\uFF08\u542B\u5386\u53F2\uFF09\uFF0C\u4E0B\u4E00\u6761\u8BC4\u8BBA\u751F\u6548\u3002`,
|
|
12468
|
+
paths.commentInstructionsFile
|
|
12469
|
+
)
|
|
12470
|
+
);
|
|
12471
|
+
})();
|
|
12000
12472
|
}).on(GS.setNoMention, ({ evt, value }) => {
|
|
12001
12473
|
if (!isAdmin(cfg, evt.operator?.openId ?? "")) return;
|
|
12002
12474
|
const on = value.v === "on";
|
|
@@ -12021,6 +12493,40 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
12021
12493
|
}
|
|
12022
12494
|
return buildGroupSettingsCard({ name: "\u672C\u7FA4", kind: "multi", autoCompact: on });
|
|
12023
12495
|
});
|
|
12496
|
+
}).on(GS.settings, ({ evt }) => {
|
|
12497
|
+
if (!isAdmin(cfg, evt.operator?.openId ?? "")) return;
|
|
12498
|
+
patch(evt, async () => {
|
|
12499
|
+
const project = await getProjectByChatId(evt.chatId);
|
|
12500
|
+
return buildGroupSettingsCard(project ?? { name: "\u672C\u7FA4", kind: "multi" });
|
|
12501
|
+
});
|
|
12502
|
+
}).on(GS.modelDefault, ({ evt }) => {
|
|
12503
|
+
if (!isAdmin(cfg, evt.operator?.openId ?? "")) return;
|
|
12504
|
+
patch(evt, async () => {
|
|
12505
|
+
const project = await getProjectByChatId(evt.chatId);
|
|
12506
|
+
if (!project) return buildGroupSettingsCard({ name: "\u672C\u7FA4", kind: "multi" });
|
|
12507
|
+
const models = await listModels(backendFor(project.backend));
|
|
12508
|
+
return buildModelDefaultCard(project, models, "group");
|
|
12509
|
+
});
|
|
12510
|
+
}).on(GS.modelDefaultSubmit, ({ evt, formValue }) => {
|
|
12511
|
+
if (!isAdmin(cfg, evt.operator?.openId ?? "")) return;
|
|
12512
|
+
const modelId = selectValue(formValue, "model");
|
|
12513
|
+
const effortRaw = asEffort(selectValue(formValue, "effort"));
|
|
12514
|
+
void (async () => {
|
|
12515
|
+
const project = await getProjectByChatId(evt.chatId);
|
|
12516
|
+
if (!project) return;
|
|
12517
|
+
const models = await listModels(backendFor(project.backend));
|
|
12518
|
+
const m = modelId ? models.find((x) => x.id === modelId && !x.hidden) : void 0;
|
|
12519
|
+
if (m) {
|
|
12520
|
+
const supported = m.supportedEfforts ?? [];
|
|
12521
|
+
const effort = effortRaw && supported.includes(effortRaw) ? effortRaw : supported.length ? m.defaultEffort : void 0;
|
|
12522
|
+
const r = await performSetModelDefault({ projectName: project.name, model: m.id, effort });
|
|
12523
|
+
if (r.ok) log.info("console", "group-model-default", { project: project.name, model: m.id, effort });
|
|
12524
|
+
}
|
|
12525
|
+
const fresh = await getProjectByChatId(evt.chatId) ?? project;
|
|
12526
|
+
await sendManagedCard(channel, evt.chatId, buildGroupSettingsCard(fresh)).catch(
|
|
12527
|
+
(e) => log.fail("console", e, { phase: "group-model-default-result" })
|
|
12528
|
+
);
|
|
12529
|
+
})();
|
|
12024
12530
|
}).on(DM.admins, ({ evt }) => {
|
|
12025
12531
|
if (!dmAdmin(evt.operator?.openId)) return;
|
|
12026
12532
|
patch(
|
|
@@ -12161,6 +12667,42 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
12161
12667
|
(e) => log.fail("console", e, { phase: "permission-result" })
|
|
12162
12668
|
);
|
|
12163
12669
|
})();
|
|
12670
|
+
}).on(DM.modelDefault, ({ evt, value }) => {
|
|
12671
|
+
if (!dmAdmin(evt.operator?.openId)) return;
|
|
12672
|
+
const name = typeof value.n === "string" ? value.n : "";
|
|
12673
|
+
patch(evt, async () => {
|
|
12674
|
+
const p = await getProjectByName(name);
|
|
12675
|
+
if (!p) return buildDmMenuCard({ webConsoleUrl: webConsoleUrl(), version: bridgeVersion() });
|
|
12676
|
+
const models = await listModels(backendFor(p.backend));
|
|
12677
|
+
return buildModelDefaultCard(p, models, "dm");
|
|
12678
|
+
});
|
|
12679
|
+
}).on(DM.modelDefaultSubmit, ({ evt, value, formValue }) => {
|
|
12680
|
+
if (!dmAdmin(evt.operator?.openId)) return;
|
|
12681
|
+
const name = typeof value.n === "string" ? value.n : "";
|
|
12682
|
+
const modelId = selectValue(formValue, "model");
|
|
12683
|
+
const effortRaw = asEffort(selectValue(formValue, "effort"));
|
|
12684
|
+
void (async () => {
|
|
12685
|
+
const p = await getProjectByName(name);
|
|
12686
|
+
if (!p) return;
|
|
12687
|
+
const models = await listModels(backendFor(p.backend));
|
|
12688
|
+
const m = modelId ? models.find((x) => x.id === modelId && !x.hidden) : void 0;
|
|
12689
|
+
let notice;
|
|
12690
|
+
if (!m) {
|
|
12691
|
+
notice = "\u26A0\uFE0F \u6240\u9009\u6A21\u578B\u65E0\u6548\u6216\u5DF2\u4E0B\u67B6\uFF0C\u672A\u4FDD\u5B58\u3002";
|
|
12692
|
+
} else {
|
|
12693
|
+
const supported = m.supportedEfforts ?? [];
|
|
12694
|
+
const effort = effortRaw && supported.includes(effortRaw) ? effortRaw : supported.length ? m.defaultEffort : void 0;
|
|
12695
|
+
const r = await performSetModelDefault({ projectName: name, model: m.id, effort });
|
|
12696
|
+
notice = r.ok ? `\u2705 \u9ED8\u8BA4\u5DF2\u8BBE\u4E3A\u300C${m.displayName}\u300D${effort ? ` \xB7 \u5F3A\u5EA6 ${effort}` : ""}\uFF0C\u65B0\u8BDD\u9898\u751F\u6548\u3002` : `\u26A0\uFE0F ${r.reason}`;
|
|
12697
|
+
if (r.ok) log.info("console", "project-model-default", { project: name, model: m.id, effort });
|
|
12698
|
+
}
|
|
12699
|
+
const fresh = await getProjectByName(name) ?? p;
|
|
12700
|
+
await sendManagedCard(
|
|
12701
|
+
channel,
|
|
12702
|
+
evt.chatId,
|
|
12703
|
+
buildProjectSettingsCard(fresh, backendDisplayName(fresh.backend), notice)
|
|
12704
|
+
).catch((e) => log.fail("console", e, { phase: "model-default-result" }));
|
|
12705
|
+
})();
|
|
12164
12706
|
});
|
|
12165
12707
|
async function resumeFromCard(evt, state, sessionId, backendId) {
|
|
12166
12708
|
const be = backendFor(backendId);
|
|
@@ -12745,18 +13287,39 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
12745
13287
|
if (!evt.mentionedBot) return log.info("comment", "skip", { reason: "not-mentioned" });
|
|
12746
13288
|
if (!SUPPORTED_FILE_TYPES.has(evt.fileType))
|
|
12747
13289
|
return log.info("comment", "skip", { reason: "unsupported-fileType", fileType: evt.fileType });
|
|
13290
|
+
const operatorId = evt.operator?.openId ?? "";
|
|
13291
|
+
if (!isAdmin(cfg, operatorId))
|
|
13292
|
+
return log.info("comment", "skip", { reason: "not-admin", sender: operatorId.slice(-6) || "(unknown)" });
|
|
12748
13293
|
const resolved = await resolveComment(channel, evt);
|
|
12749
13294
|
if (!resolved) return log.info("comment", "skip", { reason: "no-target-or-empty" });
|
|
12750
13295
|
const { target, ctx } = resolved;
|
|
12751
13296
|
log.info("comment", "parsed", { isWhole: ctx.isWhole, hasQuote: Boolean(ctx.quote) });
|
|
12752
|
-
const
|
|
12753
|
-
const
|
|
13297
|
+
const sessionKey = commentSessionKey(target.fileToken, evt.commentId);
|
|
13298
|
+
const cwd = commentCwd(paths.commentsRootDir, target.fileType, target.fileToken);
|
|
13299
|
+
const rawInstructions = await loadCommentInstructions(paths.commentInstructionsFile);
|
|
13300
|
+
const instructions = renderCommentInstructions(
|
|
13301
|
+
rawInstructions,
|
|
13302
|
+
cfg.accounts.app.tenant,
|
|
13303
|
+
target.fileType,
|
|
13304
|
+
target.fileToken
|
|
13305
|
+
);
|
|
13306
|
+
let synced = true;
|
|
13307
|
+
await syncCommentInstructions(cwd, instructions).catch((err) => {
|
|
13308
|
+
synced = false;
|
|
13309
|
+
log.warn("comment", "sync-instructions-failed", { err: err instanceof Error ? err.message : String(err) });
|
|
13310
|
+
});
|
|
13311
|
+
const facts = buildCommentPrompt(target, ctx, cfg.accounts.app.tenant);
|
|
13312
|
+
const prompt = synced ? facts : `${instructions}
|
|
13313
|
+
|
|
13314
|
+
---
|
|
13315
|
+
|
|
13316
|
+
${facts}`;
|
|
12754
13317
|
const reacted = ctx.targetReplyId ? await addCommentReaction(channel, target, ctx.targetReplyId) : false;
|
|
12755
13318
|
try {
|
|
12756
13319
|
await withDocLock(sessionKey, async () => {
|
|
12757
13320
|
const release2 = await sema.acquire();
|
|
12758
13321
|
try {
|
|
12759
|
-
const thread = await resolveDocThread(sessionKey, ctx.question);
|
|
13322
|
+
const thread = await resolveDocThread(sessionKey, cwd, instructions, ctx.question);
|
|
12760
13323
|
const rec = await getSession(sessionKey);
|
|
12761
13324
|
const run = thread.runStreamed({ text: prompt }, { model: rec?.model, effort: rec?.effort });
|
|
12762
13325
|
let state = initialState;
|
|
@@ -12770,6 +13333,7 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
12770
13333
|
if (tid) void thread.abort(tid).catch(() => void 0);
|
|
12771
13334
|
void thread.close().catch(() => void 0);
|
|
12772
13335
|
sessions.delete(sessionKey);
|
|
13336
|
+
commentInstrUsed.delete(sessionKey);
|
|
12773
13337
|
} else {
|
|
12774
13338
|
touchSession(sessionKey);
|
|
12775
13339
|
await patchSession(sessionKey, { updatedAt: Date.now() });
|
|
@@ -12807,12 +13371,15 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
12807
13371
|
});
|
|
12808
13372
|
return run;
|
|
12809
13373
|
}
|
|
12810
|
-
async function resolveDocThread(sessionKey, question) {
|
|
13374
|
+
async function resolveDocThread(sessionKey, cwd, instructions, question) {
|
|
12811
13375
|
const live = sessions.get(sessionKey);
|
|
12812
13376
|
if (live) {
|
|
12813
|
-
|
|
13377
|
+
const alive = live.isAlive();
|
|
13378
|
+
if (alive && commentInstrUsed.get(sessionKey) === instructions) return live;
|
|
13379
|
+
if (alive && commentInstrUsed.get(sessionKey) !== instructions) void live.close().catch(() => void 0);
|
|
12814
13380
|
sessions.delete(sessionKey);
|
|
12815
|
-
|
|
13381
|
+
commentInstrUsed.delete(sessionKey);
|
|
13382
|
+
log.info("agent", alive ? "comment-instr-changed-evict" : "dead-thread-evict", { sessionKey });
|
|
12816
13383
|
}
|
|
12817
13384
|
const rec = await getSession(sessionKey);
|
|
12818
13385
|
if (rec) {
|
|
@@ -12824,20 +13391,27 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
12824
13391
|
effort: rec.effort
|
|
12825
13392
|
});
|
|
12826
13393
|
trackSession(sessionKey, resumed);
|
|
13394
|
+
commentInstrUsed.set(sessionKey, instructions);
|
|
12827
13395
|
return resumed;
|
|
12828
13396
|
} catch (err) {
|
|
12829
13397
|
log.fail("agent", err, { phase: "comment-resume", sessionKey });
|
|
12830
13398
|
}
|
|
12831
13399
|
}
|
|
12832
|
-
const
|
|
12833
|
-
const
|
|
13400
|
+
const comments = getCommentsConfig(cfg);
|
|
13401
|
+
const be = backendFor(comments.backend);
|
|
13402
|
+
const { model, effort } = pickDefault(await listModels(be), {
|
|
13403
|
+
model: comments.model,
|
|
13404
|
+
effort: comments.effort
|
|
13405
|
+
});
|
|
13406
|
+
const fresh = await be.startThread({ cwd, model, effort });
|
|
12834
13407
|
trackSession(sessionKey, fresh);
|
|
13408
|
+
commentInstrUsed.set(sessionKey, instructions);
|
|
12835
13409
|
await upsertSession({
|
|
12836
13410
|
threadId: sessionKey,
|
|
12837
13411
|
chatId: sessionKey,
|
|
12838
|
-
cwd
|
|
13412
|
+
cwd,
|
|
12839
13413
|
sessionId: fresh.sessionId,
|
|
12840
|
-
backend:
|
|
13414
|
+
backend: be.id,
|
|
12841
13415
|
model,
|
|
12842
13416
|
effort,
|
|
12843
13417
|
summary: question.slice(0, 80),
|
|
@@ -13239,7 +13813,7 @@ function createAdminIpcResponder(execute, send) {
|
|
|
13239
13813
|
// src/admin/service.ts
|
|
13240
13814
|
init_bots();
|
|
13241
13815
|
init_paths();
|
|
13242
|
-
import { readFile as
|
|
13816
|
+
import { readFile as readFile13, rm as rm7 } from "fs/promises";
|
|
13243
13817
|
init_schema();
|
|
13244
13818
|
init_store();
|
|
13245
13819
|
init_schema();
|
|
@@ -13311,8 +13885,8 @@ init_logger();
|
|
|
13311
13885
|
|
|
13312
13886
|
// src/admin/host.ts
|
|
13313
13887
|
init_paths();
|
|
13314
|
-
import { readdir as
|
|
13315
|
-
import { dirname as
|
|
13888
|
+
import { readdir as readdir5, stat as stat4 } from "fs/promises";
|
|
13889
|
+
import { dirname as dirname13, join as join21, resolve as resolve8 } from "path";
|
|
13316
13890
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
13317
13891
|
import { arch, platform as platform2, release } from "os";
|
|
13318
13892
|
function toDaemonStatus(opts) {
|
|
@@ -13336,12 +13910,12 @@ async function dirBytes(dir) {
|
|
|
13336
13910
|
let total = 0;
|
|
13337
13911
|
let entries;
|
|
13338
13912
|
try {
|
|
13339
|
-
entries = await
|
|
13913
|
+
entries = await readdir5(dir);
|
|
13340
13914
|
} catch {
|
|
13341
13915
|
return 0;
|
|
13342
13916
|
}
|
|
13343
13917
|
for (const name of entries) {
|
|
13344
|
-
const full =
|
|
13918
|
+
const full = join21(dir, name);
|
|
13345
13919
|
try {
|
|
13346
13920
|
const st = await stat4(full);
|
|
13347
13921
|
if (st.isDirectory()) total += await dirBytes(full);
|
|
@@ -13351,7 +13925,7 @@ async function dirBytes(dir) {
|
|
|
13351
13925
|
}
|
|
13352
13926
|
return total;
|
|
13353
13927
|
}
|
|
13354
|
-
async function collectHostDoctor(logsDir2 =
|
|
13928
|
+
async function collectHostDoctor(logsDir2 = join21(paths.appDir, "logs")) {
|
|
13355
13929
|
return {
|
|
13356
13930
|
node: process.version,
|
|
13357
13931
|
platform: platform2(),
|
|
@@ -13364,7 +13938,7 @@ async function collectHostDoctor(logsDir2 = join20(paths.appDir, "logs")) {
|
|
|
13364
13938
|
};
|
|
13365
13939
|
}
|
|
13366
13940
|
function resolveCliBinPath3() {
|
|
13367
|
-
const distDir =
|
|
13941
|
+
const distDir = dirname13(fileURLToPath5(import.meta.url));
|
|
13368
13942
|
return resolve8(distDir, "..", "bin", "feishu-codex-bridge.mjs");
|
|
13369
13943
|
}
|
|
13370
13944
|
function buildDaemonControlCommand(action, binPath = resolveCliBinPath3(), nodePath = process.execPath) {
|
|
@@ -13412,7 +13986,7 @@ function createAdminService(deps = {}) {
|
|
|
13412
13986
|
}
|
|
13413
13987
|
async function lockFileRunState(botId) {
|
|
13414
13988
|
try {
|
|
13415
|
-
const raw = await
|
|
13989
|
+
const raw = await readFile13(botPaths(botId).processesFile, "utf8");
|
|
13416
13990
|
const rec = JSON.parse(raw);
|
|
13417
13991
|
if (typeof rec.pid === "number" && isAlive2(rec.pid)) {
|
|
13418
13992
|
return { running: true, pid: rec.pid, startedAt: rec.startedAt };
|
|
@@ -13940,7 +14514,7 @@ import { createServer } from "http";
|
|
|
13940
14514
|
import { randomUUID as randomUUID7, timingSafeEqual } from "crypto";
|
|
13941
14515
|
import { mkdirSync as mkdirSync3, watch } from "fs";
|
|
13942
14516
|
import { open as open2, stat as stat5 } from "fs/promises";
|
|
13943
|
-
import { join as
|
|
14517
|
+
import { join as join22 } from "path";
|
|
13944
14518
|
|
|
13945
14519
|
// src/web/ui.ts
|
|
13946
14520
|
var UI_PURE_JS = `
|
|
@@ -16615,7 +17189,7 @@ var SSE_INITIAL_TAIL_BYTES = 16 * 1024;
|
|
|
16615
17189
|
function createWebServer(opts) {
|
|
16616
17190
|
const token = opts.token ?? randomUUID7();
|
|
16617
17191
|
const html = opts.html ?? UI_HTML;
|
|
16618
|
-
const logDir = opts.logDir ??
|
|
17192
|
+
const logDir = opts.logDir ?? join22(paths.appDir, "logs");
|
|
16619
17193
|
const sseCleanups = /* @__PURE__ */ new Set();
|
|
16620
17194
|
const installJobs = /* @__PURE__ */ new Map();
|
|
16621
17195
|
let qrSession = null;
|
|
@@ -17253,7 +17827,7 @@ function isLoopbackOrigin(origin) {
|
|
|
17253
17827
|
}
|
|
17254
17828
|
}
|
|
17255
17829
|
function todayLogFile(dir) {
|
|
17256
|
-
return
|
|
17830
|
+
return join22(dir, `${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.log`);
|
|
17257
17831
|
}
|
|
17258
17832
|
function clampInt(raw, min, max, fallback) {
|
|
17259
17833
|
const n = Number(raw);
|
|
@@ -17456,7 +18030,7 @@ async function runSupervisor(bots) {
|
|
|
17456
18030
|
// src/core/single-instance.ts
|
|
17457
18031
|
init_paths();
|
|
17458
18032
|
import { mkdirSync as mkdirSync4, readFileSync as readFileSync6, statSync as statSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
17459
|
-
import { dirname as
|
|
18033
|
+
import { dirname as dirname14 } from "path";
|
|
17460
18034
|
var CLAIM_ATTEMPTS = 5;
|
|
17461
18035
|
var PID_REUSE_SLACK_MS = 15e3;
|
|
17462
18036
|
var EMPTY_LOCK_STALE_MS = 2e3;
|
|
@@ -17502,7 +18076,7 @@ function isLiveHolder(rec, appId) {
|
|
|
17502
18076
|
return true;
|
|
17503
18077
|
}
|
|
17504
18078
|
function acquireSingleInstanceLock(appId, file = paths.processesFile) {
|
|
17505
|
-
mkdirSync4(
|
|
18079
|
+
mkdirSync4(dirname14(file), { recursive: true });
|
|
17506
18080
|
const record = { pid: process.pid, appId, startedAt: Date.now() };
|
|
17507
18081
|
for (let attempt = 0; attempt < CLAIM_ATTEMPTS; attempt++) {
|
|
17508
18082
|
try {
|