@modelzen/feishu-codex-bridge 0.3.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +434 -68
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -78,6 +78,7 @@ import { dirname as dirname3, join as join2 } from "path";
|
|
|
78
78
|
|
|
79
79
|
// src/config/store.ts
|
|
80
80
|
import { chmod, mkdir, readFile, rename, writeFile } from "fs/promises";
|
|
81
|
+
import { randomUUID } from "crypto";
|
|
81
82
|
import { dirname as dirname2 } from "path";
|
|
82
83
|
|
|
83
84
|
// src/config/schema.ts
|
|
@@ -114,18 +115,23 @@ function getRunIdleTimeoutMs(cfg) {
|
|
|
114
115
|
const clamped = Math.min(Math.max(Math.floor(raw), 10), 1800);
|
|
115
116
|
return clamped * 1e3;
|
|
116
117
|
}
|
|
117
|
-
function isUserAllowed(cfg, senderId) {
|
|
118
|
-
const list = cfg.preferences?.access?.allowedUsers;
|
|
119
|
-
if (!list || list.length === 0) return true;
|
|
120
|
-
return list.includes(senderId);
|
|
121
|
-
}
|
|
122
118
|
function isChatAllowed(cfg, chatId) {
|
|
123
119
|
const list = cfg.preferences?.access?.allowedChats;
|
|
124
120
|
if (!list || list.length === 0) return true;
|
|
125
121
|
return list.includes(chatId);
|
|
126
122
|
}
|
|
123
|
+
function resolveOwner(cfg) {
|
|
124
|
+
const access = cfg.preferences?.access;
|
|
125
|
+
return access?.ownerOpenId ?? access?.admins?.[0];
|
|
126
|
+
}
|
|
127
127
|
function isAdmin(cfg, senderId) {
|
|
128
|
-
|
|
128
|
+
if (!senderId) return false;
|
|
129
|
+
if (senderId === resolveOwner(cfg)) return true;
|
|
130
|
+
return Boolean(cfg.preferences?.access?.admins?.includes(senderId));
|
|
131
|
+
}
|
|
132
|
+
function isUserAllowedInProject(cfg, project, senderId) {
|
|
133
|
+
if (isAdmin(cfg, senderId)) return true;
|
|
134
|
+
const list = project?.allowedUsers;
|
|
129
135
|
if (!list || list.length === 0) return true;
|
|
130
136
|
return list.includes(senderId);
|
|
131
137
|
}
|
|
@@ -174,13 +180,21 @@ exec ${sq(node)} ${sq(bridgeEntry)} secrets get "$@"
|
|
|
174
180
|
await rename(tmp, wrapperPath);
|
|
175
181
|
return wrapperPath;
|
|
176
182
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const
|
|
180
|
-
|
|
183
|
+
var saveChain = Promise.resolve();
|
|
184
|
+
function saveConfig(cfg, path = paths.configFile) {
|
|
185
|
+
const run = saveChain.then(async () => {
|
|
186
|
+
await mkdir(dirname2(path), { recursive: true });
|
|
187
|
+
const tmp = `${path}.tmp-${process.pid}-${randomUUID()}`;
|
|
188
|
+
await writeFile(tmp, `${JSON.stringify(cfg, null, 2)}
|
|
181
189
|
`, "utf8");
|
|
182
|
-
|
|
183
|
-
|
|
190
|
+
await chmod(tmp, 384);
|
|
191
|
+
await rename(tmp, path);
|
|
192
|
+
});
|
|
193
|
+
saveChain = run.then(
|
|
194
|
+
() => void 0,
|
|
195
|
+
() => void 0
|
|
196
|
+
);
|
|
197
|
+
return run;
|
|
184
198
|
}
|
|
185
199
|
|
|
186
200
|
// src/config/bots.ts
|
|
@@ -670,7 +684,7 @@ async function runRegistrationWizard() {
|
|
|
670
684
|
accounts: { app: { id: result.client_id, secret: result.client_secret, tenant } }
|
|
671
685
|
};
|
|
672
686
|
if (operatorOpenId) {
|
|
673
|
-
cfg.preferences = { access: { admins: [operatorOpenId] } };
|
|
687
|
+
cfg.preferences = { access: { ownerOpenId: operatorOpenId, admins: [operatorOpenId] } };
|
|
674
688
|
console.log(` Admin: ${operatorOpenId} (\u4F60\u81EA\u5DF1\uFF0C\u5DF2\u81EA\u52A8\u52A0\u5165\u7BA1\u7406\u5458\u540D\u5355)`);
|
|
675
689
|
} else {
|
|
676
690
|
console.log(
|
|
@@ -727,7 +741,13 @@ var JOIN_GROUP_SCOPES = [
|
|
|
727
741
|
"im:chat:readonly",
|
|
728
742
|
"im:chat.members:write_only"
|
|
729
743
|
];
|
|
730
|
-
var
|
|
744
|
+
var CONTACT_SCOPES = ["contact:user.base:readonly"];
|
|
745
|
+
var GRANT_SCOPES = [
|
|
746
|
+
...REQUIRED_SCOPES,
|
|
747
|
+
...COMMENT_SCOPES,
|
|
748
|
+
...JOIN_GROUP_SCOPES,
|
|
749
|
+
...CONTACT_SCOPES
|
|
750
|
+
];
|
|
731
751
|
var SCOPE_LABELS = {
|
|
732
752
|
"im:message.group_at_msg:readonly": "\u63A5\u6536\u7FA4\u91CC @\u673A\u5668\u4EBA \u7684\u6D88\u606F",
|
|
733
753
|
"im:message.group_msg": "\u63A5\u6536\u7FA4\u5185\u6240\u6709\u6D88\u606F\uFF08\u514D@\uFF09",
|
|
@@ -748,7 +768,8 @@ var SCOPE_LABELS = {
|
|
|
748
768
|
"cardkit:card:write": "\u4EA4\u4E92\u6309\u94AE\u5361\u7247",
|
|
749
769
|
"docs:document.comment:read": "\u8BFB\u53D6\u6587\u6863\u8BC4\u8BBA",
|
|
750
770
|
"docs:document.comment:create": "\u53D1\u8868\u6587\u6863\u8BC4\u8BBA\u56DE\u590D",
|
|
751
|
-
"wiki:wiki:readonly": "\u8BFB\u53D6\u77E5\u8BC6\u5E93\u8282\u70B9"
|
|
771
|
+
"wiki:wiki:readonly": "\u8BFB\u53D6\u77E5\u8BC6\u5E93\u8282\u70B9",
|
|
772
|
+
"contact:user.base:readonly": "\u8BFB\u53D6\u6210\u5458\u59D3\u540D\uFF08\u7BA1\u7406\u5458 / \u767D\u540D\u5355\u5C55\u793A\uFF09"
|
|
752
773
|
};
|
|
753
774
|
function labelScope(scope) {
|
|
754
775
|
const label = SCOPE_LABELS[scope];
|
|
@@ -2168,6 +2189,14 @@ function selectStatic(opts) {
|
|
|
2168
2189
|
behaviors: [{ type: "callback", value: { a: opts.actionId } }]
|
|
2169
2190
|
};
|
|
2170
2191
|
}
|
|
2192
|
+
function selectMenu(opts) {
|
|
2193
|
+
return {
|
|
2194
|
+
tag: "select_static",
|
|
2195
|
+
name: opts.name,
|
|
2196
|
+
placeholder: { tag: "plain_text", content: opts.placeholder },
|
|
2197
|
+
options: opts.options.map((o) => ({ text: { tag: "plain_text", content: o.label }, value: o.value }))
|
|
2198
|
+
};
|
|
2199
|
+
}
|
|
2171
2200
|
|
|
2172
2201
|
// src/card/command-cards.ts
|
|
2173
2202
|
var MC = {
|
|
@@ -2275,19 +2304,13 @@ function pickerTime(unixSeconds) {
|
|
|
2275
2304
|
function talkLine(noMention, tail) {
|
|
2276
2305
|
return noMention ? `\xB7 \u76F4\u63A5\u53D1\u6D88\u606F\uFF08\u514D@\uFF09\u2192 ${tail}` : `\xB7 **@\u6211 + \u5185\u5BB9** \u2192 ${tail}\uFF08\u672C\u7FA4\u9ED8\u8BA4\u9700 @\uFF1B\`/settings\` \u53EF\u5F00\u542F\u514D@\uFF09`;
|
|
2277
2306
|
}
|
|
2278
|
-
function buildHelpCard(scope, noMention = true) {
|
|
2307
|
+
function buildHelpCard(scope, noMention = true, isAdmin2 = false) {
|
|
2279
2308
|
const elements = [];
|
|
2280
2309
|
if (scope === "single") {
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
`${talkLine(noMention, "\u4EA4\u7ED9\u6211\u5904\u7406")}
|
|
2286
|
-
\xB7 \`/model\` \u2192 \u5207\u6362\u6A21\u578B / \u63A8\u7406\u5F3A\u5EA6
|
|
2287
|
-
\xB7 \`/settings\` \u2192 \u7FA4\u8BBE\u7F6E\uFF08\u514D@ \u5F00\u5173\uFF09
|
|
2288
|
-
\xB7 \`/help\` \u2192 \u8FD9\u5F20\u901F\u67E5\u5361`
|
|
2289
|
-
)
|
|
2290
|
-
);
|
|
2310
|
+
const lines = [talkLine(noMention, "\u4EA4\u7ED9\u6211\u5904\u7406"), "\xB7 `/model` \u2192 \u5207\u6362\u6A21\u578B / \u63A8\u7406\u5F3A\u5EA6"];
|
|
2311
|
+
if (isAdmin2) lines.push("\xB7 `/settings` \u2192 \u7FA4\u8BBE\u7F6E\uFF08\u514D@ \u5F00\u5173\uFF09");
|
|
2312
|
+
lines.push("\xB7 `/help` \u2192 \u8FD9\u5F20\u901F\u67E5\u5361");
|
|
2313
|
+
elements.push(md("\u{1F4AC} **\u5355\u4F1A\u8BDD\u7FA4** \u2014 \u6574\u7FA4\u5C31\u662F\u4E00\u4E2A\u4F1A\u8BDD\uFF0C\u4E0A\u4E0B\u6587\u8FDE\u7EED\u3002"), hr(), md(lines.join("\n")));
|
|
2291
2314
|
} else if (scope === "topic") {
|
|
2292
2315
|
elements.push(
|
|
2293
2316
|
md("\u{1F9F5} **\u8BDD\u9898\u5185** \u2014 \u6BCF\u4E2A\u8BDD\u9898\u662F\u4E00\u4E2A\u72EC\u7ACB\u4F1A\u8BDD\u3002"),
|
|
@@ -2300,13 +2323,10 @@ function buildHelpCard(scope, noMention = true) {
|
|
|
2300
2323
|
note("\u5F00\u65B0\u8BDD\u9898\uFF1A\u56DE\u5230\u4E3B\u7FA4\u533A @\u6211 + \u5185\u5BB9\u3002")
|
|
2301
2324
|
);
|
|
2302
2325
|
} else {
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
"\xB7 **@\u6211 + \u5185\u5BB9** \u2192 \u5F00\u4E00\u4E2A\u65B0\u8BDD\u9898\u5E76\u5F00\u59CB\n\xB7 `/resume` \u2192 \u6062\u590D\u5386\u53F2\u4F1A\u8BDD\n\xB7 `/settings` \u2192 \u7FA4\u8BBE\u7F6E\uFF08\u514D@ \u5F00\u5173\uFF09\n\xB7 `/model` \u2192 \u9700\u8981\u5728\u8BDD\u9898\u91CC\u7528\n\xB7 `/help` \u2192 \u8FD9\u5F20\u901F\u67E5\u5361"
|
|
2308
|
-
)
|
|
2309
|
-
);
|
|
2326
|
+
const lines = ["\xB7 **@\u6211 + \u5185\u5BB9** \u2192 \u5F00\u4E00\u4E2A\u65B0\u8BDD\u9898\u5E76\u5F00\u59CB"];
|
|
2327
|
+
if (isAdmin2) lines.push("\xB7 `/resume` \u2192 \u6062\u590D\u5386\u53F2\u4F1A\u8BDD", "\xB7 `/settings` \u2192 \u7FA4\u8BBE\u7F6E\uFF08\u514D@ \u5F00\u5173\uFF09");
|
|
2328
|
+
lines.push("\xB7 `/model` \u2192 \u9700\u8981\u5728\u8BDD\u9898\u91CC\u7528", "\xB7 `/help` \u2192 \u8FD9\u5F20\u901F\u67E5\u5361");
|
|
2329
|
+
elements.push(md("\u{1F465} **\u4E3B\u7FA4\u533A** \u2014 @\u6211\u5F00\u8BDD\u9898\uFF0C\u6BCF\u4E2A\u8BDD\u9898\u662F\u72EC\u7ACB\u4F1A\u8BDD\u3002"), hr(), md(lines.join("\n")));
|
|
2310
2330
|
}
|
|
2311
2331
|
return card(elements, { header: { title: "\u{1F916} \u53EF\u7528\u547D\u4EE4", template: "blue" }, summary: "\u53EF\u7528\u547D\u4EE4" });
|
|
2312
2332
|
}
|
|
@@ -3113,6 +3133,7 @@ async function uploadBuffer(channel, buffer) {
|
|
|
3113
3133
|
|
|
3114
3134
|
// src/project/registry.ts
|
|
3115
3135
|
import { mkdir as mkdir4, readFile as readFile6, rename as rename4, writeFile as writeFile4 } from "fs/promises";
|
|
3136
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
3116
3137
|
import { dirname as dirname5 } from "path";
|
|
3117
3138
|
function defaultNoMention(p) {
|
|
3118
3139
|
return !((p.origin ?? "created") === "joined" && (p.kind ?? "multi") === "single");
|
|
@@ -3128,9 +3149,18 @@ async function read() {
|
|
|
3128
3149
|
throw err;
|
|
3129
3150
|
}
|
|
3130
3151
|
}
|
|
3152
|
+
var opChain = Promise.resolve();
|
|
3153
|
+
function withLock(fn) {
|
|
3154
|
+
const run = opChain.then(fn, fn);
|
|
3155
|
+
opChain = run.then(
|
|
3156
|
+
() => void 0,
|
|
3157
|
+
() => void 0
|
|
3158
|
+
);
|
|
3159
|
+
return run;
|
|
3160
|
+
}
|
|
3131
3161
|
async function write(projects) {
|
|
3132
3162
|
await mkdir4(dirname5(paths.projectsFile), { recursive: true });
|
|
3133
|
-
const tmp = `${paths.projectsFile}.tmp-${process.pid}`;
|
|
3163
|
+
const tmp = `${paths.projectsFile}.tmp-${process.pid}-${randomUUID2()}`;
|
|
3134
3164
|
const body = { version: FILE_VERSION2, projects };
|
|
3135
3165
|
await writeFile4(tmp, `${JSON.stringify(body, null, 2)}
|
|
3136
3166
|
`, "utf8");
|
|
@@ -3146,34 +3176,41 @@ async function getProjectByName(name) {
|
|
|
3146
3176
|
return (await read()).find((p) => p.name === name);
|
|
3147
3177
|
}
|
|
3148
3178
|
async function addProject(p) {
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3179
|
+
return withLock(async () => {
|
|
3180
|
+
const projects = await read();
|
|
3181
|
+
if (projects.some((x) => x.name === p.name)) {
|
|
3182
|
+
throw new Error(`\u9879\u76EE\u540D\u300C${p.name}\u300D\u5DF2\u5B58\u5728`);
|
|
3183
|
+
}
|
|
3184
|
+
if (p.chatId) {
|
|
3185
|
+
const bound = projects.find((x) => x.chatId === p.chatId);
|
|
3186
|
+
if (bound) throw new Error(`\u8BE5\u7FA4\u5DF2\u7ED1\u5B9A\u4E3A\u9879\u76EE\u300C${bound.name}\u300D`);
|
|
3187
|
+
}
|
|
3188
|
+
projects.push(p);
|
|
3189
|
+
await write(projects);
|
|
3190
|
+
});
|
|
3159
3191
|
}
|
|
3160
3192
|
async function updateProject(name, patch) {
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3193
|
+
return withLock(async () => {
|
|
3194
|
+
const projects = await read();
|
|
3195
|
+
const p = projects.find((x) => x.name === name);
|
|
3196
|
+
if (!p) return;
|
|
3197
|
+
const actual = typeof patch === "function" ? patch(p) : patch;
|
|
3198
|
+
const target = p;
|
|
3199
|
+
for (const [k, v] of Object.entries(actual)) {
|
|
3200
|
+
if (v !== void 0) target[k] = v;
|
|
3201
|
+
}
|
|
3202
|
+
await write(projects);
|
|
3203
|
+
});
|
|
3169
3204
|
}
|
|
3170
3205
|
async function removeProject(name) {
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3206
|
+
return withLock(async () => {
|
|
3207
|
+
const projects = await read();
|
|
3208
|
+
const idx = projects.findIndex((p) => p.name === name);
|
|
3209
|
+
if (idx === -1) return void 0;
|
|
3210
|
+
const [removed] = projects.splice(idx, 1);
|
|
3211
|
+
await write(projects);
|
|
3212
|
+
return removed;
|
|
3213
|
+
});
|
|
3177
3214
|
}
|
|
3178
3215
|
|
|
3179
3216
|
// src/card/dm-cards.ts
|
|
@@ -3198,7 +3235,19 @@ var DM = {
|
|
|
3198
3235
|
setTools: "dm.set.tools",
|
|
3199
3236
|
setWatchdog: "dm.set.watchdog",
|
|
3200
3237
|
setPending: "dm.set.pending",
|
|
3201
|
-
setConcurrency: "dm.set.concurrency"
|
|
3238
|
+
setConcurrency: "dm.set.concurrency",
|
|
3239
|
+
// 权限管理:全局 admins(settings 卡进入)+ 项目响应白名单(项目列表 / 建项目完成卡进入)
|
|
3240
|
+
admins: "dm.admins",
|
|
3241
|
+
addAdminForm: "dm.admin.addForm",
|
|
3242
|
+
addAdminSubmit: "dm.admin.addSubmit",
|
|
3243
|
+
rmAdmin: "dm.admin.rm",
|
|
3244
|
+
allowlist: "dm.allowlist",
|
|
3245
|
+
addAllowedForm: "dm.allow.addForm",
|
|
3246
|
+
addAllowedSubmit: "dm.allow.addSubmit",
|
|
3247
|
+
rmAllowed: "dm.allow.rm",
|
|
3248
|
+
// 项目设置容器(项目列表 / 建项目完成卡 进入),以后的项目级设置项往这里加
|
|
3249
|
+
projectSettings: "dm.projectSettings",
|
|
3250
|
+
setNoMentionDm: "dm.proj.noMention"
|
|
3202
3251
|
};
|
|
3203
3252
|
var GS = {
|
|
3204
3253
|
setNoMention: "gs.noMention"
|
|
@@ -3464,7 +3513,13 @@ function buildNewProjectDoneCard(p) {
|
|
|
3464
3513
|
note(`\u{1F4C2} \`${p.cwd}\` \xB7 ${kindLabel(p.kind)}`),
|
|
3465
3514
|
md(p.chatId ? "\u{1F449} \u53BB\u7FA4\u91CC **@\u6211** \u5E72\u6D3B\u3002" : "\u53D1\u6211\u4EFB\u610F\u6D88\u606F\u53EF\u518D\u6B21\u6253\u5F00\u7BA1\u7406\u53F0\u3002")
|
|
3466
3515
|
];
|
|
3467
|
-
if (p.chatId)
|
|
3516
|
+
if (p.chatId)
|
|
3517
|
+
elements.push(
|
|
3518
|
+
actions([
|
|
3519
|
+
linkButton("\u{1F4AC} \u6253\u5F00\u7FA4\u804A", openChatUrl(p.chatId), "primary"),
|
|
3520
|
+
button("\u2699\uFE0F \u9879\u76EE\u8BBE\u7F6E", { a: DM.projectSettings, n: p.name })
|
|
3521
|
+
])
|
|
3522
|
+
);
|
|
3468
3523
|
return card(elements, { header: { title, template: "green" } });
|
|
3469
3524
|
}
|
|
3470
3525
|
function buildProjectListCard(projects, sessionsByChat = /* @__PURE__ */ new Map()) {
|
|
@@ -3495,6 +3550,7 @@ function buildProjectListCard(projects, sessionsByChat = /* @__PURE__ */ new Map
|
|
|
3495
3550
|
}
|
|
3496
3551
|
const row = [];
|
|
3497
3552
|
if (p.chatId) row.push(linkButton("\u{1F4AC} \u6253\u5F00\u7FA4\u804A", openChatUrl(p.chatId)));
|
|
3553
|
+
row.push(button("\u2699\uFE0F \u8BBE\u7F6E", { a: DM.projectSettings, n: p.name }));
|
|
3498
3554
|
row.push(button("\u{1F5D1} \u5220\u9664", { a: DM.rmConfirm, n: p.name }, "danger"));
|
|
3499
3555
|
elements.push(actions(row));
|
|
3500
3556
|
elements.push(hr());
|
|
@@ -3549,7 +3605,8 @@ function buildSettingsCard(cfg) {
|
|
|
3549
3605
|
{ label: "20", value: "20" }
|
|
3550
3606
|
]),
|
|
3551
3607
|
note("\u26A0\uFE0F \u5047\u6B7B\u8D85\u65F6 / \u5E76\u53D1\u4E0A\u9650 \u6539\u540E\u9700**\u91CD\u542F**\u751F\u6548\uFF1B\u5DE5\u5177\u663E\u793A / \u8FD0\u884C\u4E2D\u65B0\u6D88\u606F \u5373\u65F6\u751F\u6548\u3002"),
|
|
3552
|
-
|
|
3608
|
+
hr(),
|
|
3609
|
+
actions([button("\u{1F46E} \u7BA1\u7406\u5458", { a: DM.admins }), button("\u2B05\uFE0F \u83DC\u5355", { a: DM.menu })])
|
|
3553
3610
|
],
|
|
3554
3611
|
{ header: { title: "\u2699\uFE0F \u8BBE\u7F6E", template: "blue" } }
|
|
3555
3612
|
);
|
|
@@ -3572,6 +3629,146 @@ function buildGroupSettingsCard(project) {
|
|
|
3572
3629
|
{ header: { title: "\u2699\uFE0F \u7FA4\u8BBE\u7F6E", template: "blue" } }
|
|
3573
3630
|
);
|
|
3574
3631
|
}
|
|
3632
|
+
function memberName(names, id) {
|
|
3633
|
+
return names.get(id) ?? `\u2026${id.slice(-6)}`;
|
|
3634
|
+
}
|
|
3635
|
+
function buildAdminsCard(cfg, names) {
|
|
3636
|
+
const owner = resolveOwner(cfg);
|
|
3637
|
+
const admins = cfg.preferences?.access?.admins ?? [];
|
|
3638
|
+
const elements = [md("**\u7BA1\u7406\u5458\u540D\u5355** \xB7 \u672C bot \u5168\u5C40\uFF08\u53EF\u79C1\u804A\u7BA1\u7406 / \u5EFA\u9879\u76EE / \u9500\u6BC1\u64CD\u4F5C\uFF09"), hr()];
|
|
3639
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3640
|
+
if (owner) {
|
|
3641
|
+
seen.add(owner);
|
|
3642
|
+
elements.push(actions([md(`\u{1F451} **${memberName(names, owner)}** \xB7 Bot \u62E5\u6709\u8005\uFF08\u6CE8\u518C\u8005\uFF09`)]));
|
|
3643
|
+
}
|
|
3644
|
+
let extra = 0;
|
|
3645
|
+
for (const id of admins) {
|
|
3646
|
+
if (seen.has(id)) continue;
|
|
3647
|
+
seen.add(id);
|
|
3648
|
+
extra++;
|
|
3649
|
+
elements.push(actions([md(memberName(names, id)), button("\u{1F5D1} \u79FB\u9664", { a: DM.rmAdmin, u: id }, "danger")]));
|
|
3650
|
+
}
|
|
3651
|
+
if (extra === 0) elements.push(note("\u6682\u65E0\u989D\u5916\u7BA1\u7406\u5458\u3002"));
|
|
3652
|
+
elements.push(
|
|
3653
|
+
hr(),
|
|
3654
|
+
actions([button("\u2795 \u6DFB\u52A0\u7BA1\u7406\u5458", { a: DM.addAdminForm }, "primary"), button("\u2B05\uFE0F \u8BBE\u7F6E", { a: DM.settings })]),
|
|
3655
|
+
note("\u{1F451} Bot \u62E5\u6709\u8005\uFF08\u6CE8\u518C\u6B64 bot \u7684\u4EBA\uFF09\u6052\u4E3A\u7BA1\u7406\u5458\uFF0C\u4E0D\u53EF\u79FB\u9664\uFF1B\u540D\u5355\u4E3A\u7A7A\u65F6\u4EC5\u62E5\u6709\u8005\u53EF\u7BA1\u7406\u3002")
|
|
3656
|
+
);
|
|
3657
|
+
return card(elements, { header: { title: "\u{1F46E} \u7BA1\u7406\u5458", template: "blue" } });
|
|
3658
|
+
}
|
|
3659
|
+
function buildAddAdminCard(members) {
|
|
3660
|
+
const MAX = 50;
|
|
3661
|
+
const shown = members.slice(0, MAX);
|
|
3662
|
+
const formEls = [];
|
|
3663
|
+
if (shown.length > 0) {
|
|
3664
|
+
formEls.push(
|
|
3665
|
+
selectMenu({
|
|
3666
|
+
name: "pick",
|
|
3667
|
+
placeholder: "\u4ECE\u9879\u76EE\u7FA4\u6210\u5458\u9009\u62E9",
|
|
3668
|
+
options: shown.map((m) => ({ label: m.name, value: m.openId }))
|
|
3669
|
+
})
|
|
3670
|
+
);
|
|
3671
|
+
}
|
|
3672
|
+
formEls.push(
|
|
3673
|
+
input({
|
|
3674
|
+
name: "open_id",
|
|
3675
|
+
label: shown.length ? "\u6216\u76F4\u63A5\u8F93\u5165 open_id" : "\u8F93\u5165 open_id\uFF08\u672A\u8BFB\u53D6\u5230\u9879\u76EE\u7FA4\u6210\u5458\uFF09",
|
|
3676
|
+
placeholder: "ou_xxx"
|
|
3677
|
+
}),
|
|
3678
|
+
actions([submitButton("\u2705 \u786E\u8BA4\u6DFB\u52A0", { a: DM.addAdminSubmit }, "primary", "submit_admin")])
|
|
3679
|
+
);
|
|
3680
|
+
const tail = [];
|
|
3681
|
+
if (members.length > MAX) tail.push(note(`\u5019\u9009\u8F83\u591A\uFF0C\u4EC5\u5217\u524D ${MAX} \u4E2A\uFF1B\u5176\u4F59\u8BF7\u76F4\u63A5\u8F93\u5165 open_id\u3002`));
|
|
3682
|
+
return card(
|
|
3683
|
+
[
|
|
3684
|
+
md("**\u6DFB\u52A0\u7BA1\u7406\u5458** \xB7 \u4ECE\u9879\u76EE\u7FA4\u6210\u5458\u9009\uFF0C\u6216\u8F93\u5165 open_id"),
|
|
3685
|
+
form("add_admin", formEls),
|
|
3686
|
+
...tail,
|
|
3687
|
+
actions([button("\u2B05\uFE0F \u53D6\u6D88", { a: DM.admins })])
|
|
3688
|
+
],
|
|
3689
|
+
{ header: { title: "\u2795 \u6DFB\u52A0\u7BA1\u7406\u5458", template: "blue" } }
|
|
3690
|
+
);
|
|
3691
|
+
}
|
|
3692
|
+
function buildProjectSettingsCard(project) {
|
|
3693
|
+
const kind = project.kind ?? "multi";
|
|
3694
|
+
const noMention = project.noMention ?? defaultNoMention(project);
|
|
3695
|
+
return card(
|
|
3696
|
+
[
|
|
3697
|
+
md(`**\u9879\u76EE\u8BBE\u7F6E** \xB7 ${project.name}`),
|
|
3698
|
+
note(`${kindLabel(kind)}${project.cwd ? ` \xB7 \u{1F4C2} \`${project.cwd}\`` : ""}`),
|
|
3699
|
+
hr(),
|
|
3700
|
+
md("\u270B \u514D@\uFF08\u4E0D\u7528 @ \u4E5F\u56DE\u590D\uFF09"),
|
|
3701
|
+
actions([
|
|
3702
|
+
button("\u5F00", { a: DM.setNoMentionDm, v: "on", n: project.name }, noMention ? "primary" : "default"),
|
|
3703
|
+
button("\u5173", { a: DM.setNoMentionDm, v: "off", n: project.name }, noMention ? "default" : "primary")
|
|
3704
|
+
]),
|
|
3705
|
+
note(
|
|
3706
|
+
kind === "single" ? "\u5F00\u542F\u540E\uFF1A\u672C\u7FA4\u6240\u6709\u6D88\u606F(\u4E0D\u7528 @)\u90FD\u4EA4\u7ED9\u6211\u5904\u7406\u3002" : "\u5F00\u542F\u540E\uFF1A\u8BDD\u9898\u5185\u6D88\u606F(\u4E0D\u7528 @)\u90FD\u5904\u7406\uFF1B**\u5F00\u65B0\u8BDD\u9898\u4ECD\u9700 @\u6211**\u3002"
|
|
3707
|
+
),
|
|
3708
|
+
hr(),
|
|
3709
|
+
actions([button("\u{1F6E1} \u54CD\u5E94\u767D\u540D\u5355", { a: DM.allowlist, n: project.name }, "primary")]),
|
|
3710
|
+
note("\u8BBE\u7F6E\u8C01\u80FD\u8BA9\u6211\u5728\u672C\u7FA4\u54CD\u5E94 / \u8DD1 codex\uFF08\u7A7A = \u6240\u6709\u4EBA\uFF09\u3002"),
|
|
3711
|
+
hr(),
|
|
3712
|
+
actions([button("\u2B05\uFE0F \u9879\u76EE\u5217\u8868", { a: DM.projects })])
|
|
3713
|
+
],
|
|
3714
|
+
{ header: { title: "\u2699\uFE0F \u9879\u76EE\u8BBE\u7F6E", template: "blue" } }
|
|
3715
|
+
);
|
|
3716
|
+
}
|
|
3717
|
+
function buildAllowlistCard(project, names) {
|
|
3718
|
+
const list = project.allowedUsers ?? [];
|
|
3719
|
+
const elements = [md(`**\u54CD\u5E94\u767D\u540D\u5355** \xB7 ${project.name}`), note("\u8C01\u80FD\u8BA9\u6211\u5728\u672C\u7FA4\u54CD\u5E94 / \u8DD1 codex"), hr()];
|
|
3720
|
+
if (list.length === 0) {
|
|
3721
|
+
elements.push(note("\u5F53\u524D**\u6240\u6709\u4EBA**\u53EF\u7528\uFF08\u7BA1\u7406\u5458\u59CB\u7EC8\u53EF\u7528\uFF09\u3002"));
|
|
3722
|
+
} else {
|
|
3723
|
+
for (const id of list) {
|
|
3724
|
+
elements.push(
|
|
3725
|
+
actions([md(memberName(names, id)), button("\u{1F5D1} \u79FB\u9664", { a: DM.rmAllowed, u: id, n: project.name }, "danger")])
|
|
3726
|
+
);
|
|
3727
|
+
}
|
|
3728
|
+
}
|
|
3729
|
+
elements.push(
|
|
3730
|
+
hr(),
|
|
3731
|
+
actions([
|
|
3732
|
+
button("\u2795 \u6DFB\u52A0", { a: DM.addAllowedForm, n: project.name }, "primary"),
|
|
3733
|
+
button("\u2B05\uFE0F \u8BBE\u7F6E", { a: DM.projectSettings, n: project.name })
|
|
3734
|
+
]),
|
|
3735
|
+
note("\u7BA1\u7406\u5458\u59CB\u7EC8\u53EF\u7528\uFF0C\u4E0D\u53D7\u6B64\u540D\u5355\u9650\u5236\uFF1B\u540D\u5355\u4E3A\u7A7A = \u6240\u6709\u4EBA\u53EF\u7528\u3002")
|
|
3736
|
+
);
|
|
3737
|
+
return card(elements, { header: { title: "\u{1F6E1} \u54CD\u5E94\u767D\u540D\u5355", template: "blue" } });
|
|
3738
|
+
}
|
|
3739
|
+
function buildAddAllowedCard(projectName, members) {
|
|
3740
|
+
const MAX = 50;
|
|
3741
|
+
const shown = members.slice(0, MAX);
|
|
3742
|
+
const formEls = [];
|
|
3743
|
+
if (shown.length > 0) {
|
|
3744
|
+
formEls.push(
|
|
3745
|
+
selectMenu({
|
|
3746
|
+
name: "pick",
|
|
3747
|
+
placeholder: "\u4ECE\u7FA4\u6210\u5458\u9009\u62E9",
|
|
3748
|
+
options: shown.map((m) => ({ label: m.name, value: m.openId }))
|
|
3749
|
+
})
|
|
3750
|
+
);
|
|
3751
|
+
}
|
|
3752
|
+
formEls.push(
|
|
3753
|
+
input({
|
|
3754
|
+
name: "open_id",
|
|
3755
|
+
label: shown.length ? "\u6216\u76F4\u63A5\u8F93\u5165 open_id" : "\u8F93\u5165 open_id\uFF08\u672A\u8BFB\u53D6\u5230\u7FA4\u6210\u5458\uFF09",
|
|
3756
|
+
placeholder: "ou_xxx"
|
|
3757
|
+
}),
|
|
3758
|
+
actions([submitButton("\u2705 \u786E\u8BA4\u6DFB\u52A0", { a: DM.addAllowedSubmit, n: projectName }, "primary", "submit_allowed")])
|
|
3759
|
+
);
|
|
3760
|
+
const tail = [];
|
|
3761
|
+
if (members.length > MAX) tail.push(note(`\u7FA4\u6210\u5458\u8F83\u591A\uFF0C\u4EC5\u5217\u524D ${MAX} \u4E2A\uFF1B\u5176\u4F59\u8BF7\u76F4\u63A5\u8F93\u5165 open_id\u3002`));
|
|
3762
|
+
return card(
|
|
3763
|
+
[
|
|
3764
|
+
md(`**\u6DFB\u52A0\u53EF\u4F7F\u7528\u300C${projectName}\u300D\u7684\u4EBA**`),
|
|
3765
|
+
form("add_allowed", formEls),
|
|
3766
|
+
...tail,
|
|
3767
|
+
actions([button("\u2B05\uFE0F \u53D6\u6D88", { a: DM.allowlist, n: projectName })])
|
|
3768
|
+
],
|
|
3769
|
+
{ header: { title: "\u2795 \u6DFB\u52A0\u767D\u540D\u5355\u6210\u5458", template: "blue" } }
|
|
3770
|
+
);
|
|
3771
|
+
}
|
|
3575
3772
|
|
|
3576
3773
|
// src/service/update.ts
|
|
3577
3774
|
import { existsSync as existsSync6, readFileSync as readFileSync3 } from "fs";
|
|
@@ -4845,6 +5042,59 @@ var Semaphore = class {
|
|
|
4845
5042
|
};
|
|
4846
5043
|
|
|
4847
5044
|
// src/bot/handle-message.ts
|
|
5045
|
+
async function resolveNames(channel, ids) {
|
|
5046
|
+
const uniq = [...new Set(ids.filter((x) => Boolean(x)))];
|
|
5047
|
+
const out = /* @__PURE__ */ new Map();
|
|
5048
|
+
if (uniq.length === 0) return out;
|
|
5049
|
+
try {
|
|
5050
|
+
const r = await channel.rawClient.contact.v3.user.batch({
|
|
5051
|
+
params: { user_ids: uniq, user_id_type: "open_id" }
|
|
5052
|
+
});
|
|
5053
|
+
for (const it of r.data?.items ?? []) {
|
|
5054
|
+
if (it.open_id && it.name) out.set(it.open_id, it.name);
|
|
5055
|
+
}
|
|
5056
|
+
} catch (err) {
|
|
5057
|
+
log.info("console", "resolve-names-fail", { n: uniq.length, err: String(err) });
|
|
5058
|
+
}
|
|
5059
|
+
return out;
|
|
5060
|
+
}
|
|
5061
|
+
async function fetchChatMembers(channel, chatId) {
|
|
5062
|
+
try {
|
|
5063
|
+
const r = await channel.rawClient.im.v1.chatMembers.get({
|
|
5064
|
+
path: { chat_id: chatId },
|
|
5065
|
+
params: { member_id_type: "open_id", page_size: 100 }
|
|
5066
|
+
});
|
|
5067
|
+
const out = [];
|
|
5068
|
+
for (const it of r.data?.items ?? []) {
|
|
5069
|
+
if (it.member_id) out.push({ openId: it.member_id, name: it.name || `\u2026${it.member_id.slice(-6)}` });
|
|
5070
|
+
}
|
|
5071
|
+
return out;
|
|
5072
|
+
} catch (err) {
|
|
5073
|
+
log.info("console", "fetch-members-fail", { chatId: chatId.slice(-6), err: String(err) });
|
|
5074
|
+
return [];
|
|
5075
|
+
}
|
|
5076
|
+
}
|
|
5077
|
+
async function fetchAllProjectMembers(channel) {
|
|
5078
|
+
const projects = await listProjects();
|
|
5079
|
+
const lists = await Promise.all(projects.filter((p) => p.chatId).map((p) => fetchChatMembers(channel, p.chatId)));
|
|
5080
|
+
const seen = /* @__PURE__ */ new Map();
|
|
5081
|
+
for (const members of lists) {
|
|
5082
|
+
for (const m of members) if (!seen.has(m.openId)) seen.set(m.openId, m.name);
|
|
5083
|
+
}
|
|
5084
|
+
return [...seen].map(([openId, name]) => ({ openId, name }));
|
|
5085
|
+
}
|
|
5086
|
+
function pickOpenId(formValue) {
|
|
5087
|
+
const raw = formValue?.pick;
|
|
5088
|
+
const cands = Array.isArray(raw) ? raw : [raw];
|
|
5089
|
+
for (const c of cands) {
|
|
5090
|
+
if (typeof c === "string" && c.startsWith("ou_")) return c;
|
|
5091
|
+
if (c && typeof c === "object") {
|
|
5092
|
+
const o = c;
|
|
5093
|
+
for (const v of [o.open_id, o.id, o.value]) if (typeof v === "string" && v.startsWith("ou_")) return v;
|
|
5094
|
+
}
|
|
5095
|
+
}
|
|
5096
|
+
return void 0;
|
|
5097
|
+
}
|
|
4848
5098
|
function createOrchestrator(channel, cfg, fallbackCwd) {
|
|
4849
5099
|
const backend = createBackend();
|
|
4850
5100
|
const sessions = /* @__PURE__ */ new Map();
|
|
@@ -4922,7 +5172,7 @@ function createOrchestrator(channel, cfg, fallbackCwd) {
|
|
|
4922
5172
|
}
|
|
4923
5173
|
const project = await getProjectByChatId(msg.chatId);
|
|
4924
5174
|
if (!msg.mentionedBot && !(project && shouldRespondWithoutMention(project, msg))) return;
|
|
4925
|
-
if (!isChatAllowed(cfg, msg.chatId) || !
|
|
5175
|
+
if (!isChatAllowed(cfg, msg.chatId) || !isUserAllowedInProject(cfg, project, msg.senderId)) {
|
|
4926
5176
|
log.info("intake", "reject", { reason: "not_allowed", chatId: msg.chatId.slice(-6) });
|
|
4927
5177
|
return;
|
|
4928
5178
|
}
|
|
@@ -4996,9 +5246,13 @@ function createOrchestrator(channel, cfg, fallbackCwd) {
|
|
|
4996
5246
|
if ((project.kind ?? "multi") === "single") return true;
|
|
4997
5247
|
return Boolean(msg.threadId) || parseCommand(msg.content.trim()) !== null;
|
|
4998
5248
|
}
|
|
5249
|
+
async function denyAdminCommand(msg, cmd) {
|
|
5250
|
+
await channel.send(msg.chatId, { markdown: `\u26A0\uFE0F \`/${cmd}\` \u4EC5 bot \u7BA1\u7406\u5458\u53EF\u7528\u3002` }, { replyTo: msg.messageId }).catch(() => void 0);
|
|
5251
|
+
log.info("intake", "cmd-denied", { cmd });
|
|
5252
|
+
}
|
|
4999
5253
|
async function postGroupSettings(msg, project) {
|
|
5000
5254
|
if (!isAdmin(cfg, msg.senderId)) {
|
|
5001
|
-
await
|
|
5255
|
+
await denyAdminCommand(msg, "settings");
|
|
5002
5256
|
return;
|
|
5003
5257
|
}
|
|
5004
5258
|
if (!project) {
|
|
@@ -5150,6 +5404,10 @@ function createOrchestrator(channel, cfg, fallbackCwd) {
|
|
|
5150
5404
|
}).catch((err) => log.fail("intake", err));
|
|
5151
5405
|
}
|
|
5152
5406
|
async function postResumeCard(msg) {
|
|
5407
|
+
if (!isAdmin(cfg, msg.senderId)) {
|
|
5408
|
+
await denyAdminCommand(msg, "resume");
|
|
5409
|
+
return;
|
|
5410
|
+
}
|
|
5153
5411
|
await withTrace({ chatId: msg.chatId, msgId: msg.messageId }, async () => {
|
|
5154
5412
|
const project = await getProjectByChatId(msg.chatId);
|
|
5155
5413
|
const cwd = project?.cwd ?? fallbackCwd;
|
|
@@ -5191,7 +5449,7 @@ function createOrchestrator(channel, cfg, fallbackCwd) {
|
|
|
5191
5449
|
async function postHelpCard(msg, scope, inThread = false, project) {
|
|
5192
5450
|
const noMention = project ? project.noMention ?? defaultNoMention(project) : true;
|
|
5193
5451
|
await withTrace({ chatId: msg.chatId, msgId: msg.messageId }, async () => {
|
|
5194
|
-
await sendManagedCard(channel, msg.chatId, buildHelpCard(scope, noMention), msg.messageId, inThread).catch(
|
|
5452
|
+
await sendManagedCard(channel, msg.chatId, buildHelpCard(scope, noMention, isAdmin(cfg, msg.senderId)), msg.messageId, inThread).catch(
|
|
5195
5453
|
(err) => log.fail("card", err, { cmd: "help", scope })
|
|
5196
5454
|
);
|
|
5197
5455
|
log.info("card", "help", { scope });
|
|
@@ -5230,7 +5488,7 @@ function createOrchestrator(channel, cfg, fallbackCwd) {
|
|
|
5230
5488
|
return void 0;
|
|
5231
5489
|
}
|
|
5232
5490
|
const op = evt.operator?.openId ?? "";
|
|
5233
|
-
if (op !== state.requesterOpenId || !isChatAllowed(cfg, state.chatId)
|
|
5491
|
+
if (op !== state.requesterOpenId || !isChatAllowed(cfg, state.chatId)) {
|
|
5234
5492
|
log.info("card", "action-denied", { reason: "not-allowed" });
|
|
5235
5493
|
return void 0;
|
|
5236
5494
|
}
|
|
@@ -5266,7 +5524,7 @@ function createOrchestrator(channel, cfg, fallbackCwd) {
|
|
|
5266
5524
|
settleUpdate(evt.messageId, buildResumeLaunchingCard(state));
|
|
5267
5525
|
void resumeFromCard(evt, state, codexThreadId);
|
|
5268
5526
|
});
|
|
5269
|
-
const runAllowed = (evt) => isChatAllowed(cfg, evt.chatId)
|
|
5527
|
+
const runAllowed = (evt) => isChatAllowed(cfg, evt.chatId);
|
|
5270
5528
|
const runOwnerOrAdmin = (evt, ownerOpenId) => {
|
|
5271
5529
|
if (!runAllowed(evt)) return false;
|
|
5272
5530
|
const op = evt.operator?.openId ?? "";
|
|
@@ -5281,6 +5539,15 @@ function createOrchestrator(channel, cfg, fallbackCwd) {
|
|
|
5281
5539
|
});
|
|
5282
5540
|
const dmAdmin = (openId) => isAdmin(cfg, openId ?? "");
|
|
5283
5541
|
const patch = (evt, c) => settleUpdate(evt.messageId, c, evt.chatId);
|
|
5542
|
+
const namesWithOperator = async (evt, ids) => {
|
|
5543
|
+
const m = await resolveNames(channel, ids);
|
|
5544
|
+
if (ids.some((id) => id && !m.has(id))) {
|
|
5545
|
+
for (const mem of await fetchAllProjectMembers(channel)) if (!m.has(mem.openId)) m.set(mem.openId, mem.name);
|
|
5546
|
+
}
|
|
5547
|
+
const op = evt.operator;
|
|
5548
|
+
if (op?.openId && op.name && !m.has(op.openId)) m.set(op.openId, op.name);
|
|
5549
|
+
return m;
|
|
5550
|
+
};
|
|
5284
5551
|
function applyPref(evt, mut) {
|
|
5285
5552
|
if (!dmAdmin(evt.operator?.openId)) return;
|
|
5286
5553
|
const prefs = { ...cfg.preferences ?? {} };
|
|
@@ -5504,6 +5771,107 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
5504
5771
|
}
|
|
5505
5772
|
return buildGroupSettingsCard({ name: "\u672C\u7FA4", kind: "multi", noMention: on });
|
|
5506
5773
|
});
|
|
5774
|
+
}).on(DM.admins, ({ evt }) => {
|
|
5775
|
+
if (!dmAdmin(evt.operator?.openId)) return;
|
|
5776
|
+
patch(
|
|
5777
|
+
evt,
|
|
5778
|
+
async () => buildAdminsCard(cfg, await namesWithOperator(evt, [resolveOwner(cfg), ...cfg.preferences?.access?.admins ?? []]))
|
|
5779
|
+
);
|
|
5780
|
+
}).on(DM.addAdminForm, ({ evt }) => {
|
|
5781
|
+
if (!dmAdmin(evt.operator?.openId)) return;
|
|
5782
|
+
patch(evt, async () => {
|
|
5783
|
+
const all = await fetchAllProjectMembers(channel);
|
|
5784
|
+
const members = all.filter((m) => !isAdmin(cfg, m.openId));
|
|
5785
|
+
return buildAddAdminCard(members);
|
|
5786
|
+
});
|
|
5787
|
+
}).on(DM.addAdminSubmit, ({ evt, formValue }) => {
|
|
5788
|
+
if (!dmAdmin(evt.operator?.openId)) return;
|
|
5789
|
+
const manual = String(formValue?.open_id ?? "").trim();
|
|
5790
|
+
const id = manual.startsWith("ou_") ? manual : pickOpenId(formValue);
|
|
5791
|
+
log.info("console", "admin-add", { picked: id?.slice(-6) ?? null });
|
|
5792
|
+
void (async () => {
|
|
5793
|
+
if (id) {
|
|
5794
|
+
const access = { ...cfg.preferences?.access ?? {} };
|
|
5795
|
+
access.ownerOpenId ??= resolveOwner(cfg);
|
|
5796
|
+
access.admins = Array.from(/* @__PURE__ */ new Set([...access.admins ?? [], id]));
|
|
5797
|
+
cfg.preferences = { ...cfg.preferences ?? {}, access };
|
|
5798
|
+
await saveConfig(cfg).catch((e) => log.fail("console", e, { phase: "save-config" }));
|
|
5799
|
+
}
|
|
5800
|
+
const ids = [resolveOwner(cfg), ...cfg.preferences?.access?.admins ?? []];
|
|
5801
|
+
const next = buildAdminsCard(cfg, await namesWithOperator(evt, ids));
|
|
5802
|
+
await sendManagedCard(channel, evt.chatId, next).catch((e) => log.fail("console", e, { phase: "admin-add-result" }));
|
|
5803
|
+
})();
|
|
5804
|
+
}).on(DM.rmAdmin, ({ evt, value }) => {
|
|
5805
|
+
if (!dmAdmin(evt.operator?.openId)) return;
|
|
5806
|
+
const id = typeof value.u === "string" ? value.u : "";
|
|
5807
|
+
patch(evt, async () => {
|
|
5808
|
+
if (id && id !== resolveOwner(cfg)) {
|
|
5809
|
+
const access = { ...cfg.preferences?.access ?? {} };
|
|
5810
|
+
access.ownerOpenId ??= resolveOwner(cfg);
|
|
5811
|
+
access.admins = (access.admins ?? []).filter((x) => x !== id);
|
|
5812
|
+
cfg.preferences = { ...cfg.preferences ?? {}, access };
|
|
5813
|
+
await saveConfig(cfg).catch((e) => log.fail("console", e, { phase: "save-config" }));
|
|
5814
|
+
}
|
|
5815
|
+
const ids = [resolveOwner(cfg), ...cfg.preferences?.access?.admins ?? []];
|
|
5816
|
+
return buildAdminsCard(cfg, await namesWithOperator(evt, ids));
|
|
5817
|
+
});
|
|
5818
|
+
}).on(DM.allowlist, ({ evt, value }) => {
|
|
5819
|
+
if (!dmAdmin(evt.operator?.openId)) return;
|
|
5820
|
+
const name = typeof value.n === "string" ? value.n : "";
|
|
5821
|
+
patch(evt, async () => {
|
|
5822
|
+
const p = await getProjectByName(name);
|
|
5823
|
+
if (!p) return buildDmMenuCard();
|
|
5824
|
+
return buildAllowlistCard(p, await namesWithOperator(evt, p.allowedUsers ?? []));
|
|
5825
|
+
});
|
|
5826
|
+
}).on(DM.addAllowedForm, ({ evt, value }) => {
|
|
5827
|
+
if (!dmAdmin(evt.operator?.openId)) return;
|
|
5828
|
+
const name = typeof value.n === "string" ? value.n : "";
|
|
5829
|
+
if (!name) return;
|
|
5830
|
+
patch(evt, async () => {
|
|
5831
|
+
const p = await getProjectByName(name);
|
|
5832
|
+
const members = p?.chatId ? await fetchChatMembers(channel, p.chatId) : [];
|
|
5833
|
+
return buildAddAllowedCard(name, members);
|
|
5834
|
+
});
|
|
5835
|
+
}).on(DM.addAllowedSubmit, ({ evt, value, formValue }) => {
|
|
5836
|
+
if (!dmAdmin(evt.operator?.openId)) return;
|
|
5837
|
+
const name = typeof value.n === "string" ? value.n : "";
|
|
5838
|
+
const manual = String(formValue?.open_id ?? "").trim();
|
|
5839
|
+
const id = manual.startsWith("ou_") ? manual : pickOpenId(formValue);
|
|
5840
|
+
log.info("console", "allow-add", { project: name, picked: id?.slice(-6) ?? null });
|
|
5841
|
+
void (async () => {
|
|
5842
|
+
if (id) await updateProject(name, (p) => ({ allowedUsers: Array.from(/* @__PURE__ */ new Set([...p.allowedUsers ?? [], id])) }));
|
|
5843
|
+
const fresh = await getProjectByName(name);
|
|
5844
|
+
if (!fresh) return;
|
|
5845
|
+
const card2 = buildAllowlistCard(fresh, await namesWithOperator(evt, fresh.allowedUsers ?? []));
|
|
5846
|
+
await sendManagedCard(channel, evt.chatId, card2).catch((e) => log.fail("console", e, { phase: "allow-add-result" }));
|
|
5847
|
+
})();
|
|
5848
|
+
}).on(DM.rmAllowed, ({ evt, value }) => {
|
|
5849
|
+
if (!dmAdmin(evt.operator?.openId)) return;
|
|
5850
|
+
const id = typeof value.u === "string" ? value.u : "";
|
|
5851
|
+
const name = typeof value.n === "string" ? value.n : "";
|
|
5852
|
+
patch(evt, async () => {
|
|
5853
|
+
await updateProject(name, (p) => ({ allowedUsers: (p.allowedUsers ?? []).filter((x) => x !== id) }));
|
|
5854
|
+
const fresh = await getProjectByName(name);
|
|
5855
|
+
if (!fresh) return buildDmMenuCard();
|
|
5856
|
+
return buildAllowlistCard(fresh, await namesWithOperator(evt, fresh.allowedUsers ?? []));
|
|
5857
|
+
});
|
|
5858
|
+
}).on(DM.projectSettings, ({ evt, value }) => {
|
|
5859
|
+
if (!dmAdmin(evt.operator?.openId)) return;
|
|
5860
|
+
const name = typeof value.n === "string" ? value.n : "";
|
|
5861
|
+
patch(evt, async () => {
|
|
5862
|
+
const p = await getProjectByName(name);
|
|
5863
|
+
return p ? buildProjectSettingsCard(p) : buildDmMenuCard();
|
|
5864
|
+
});
|
|
5865
|
+
}).on(DM.setNoMentionDm, ({ evt, value }) => {
|
|
5866
|
+
if (!dmAdmin(evt.operator?.openId)) return;
|
|
5867
|
+
const name = typeof value.n === "string" ? value.n : "";
|
|
5868
|
+
const on = value.v === "on";
|
|
5869
|
+
patch(evt, async () => {
|
|
5870
|
+
const p = await getProjectByName(name);
|
|
5871
|
+
if (!p) return buildDmMenuCard();
|
|
5872
|
+
await updateProject(name, { noMention: on });
|
|
5873
|
+
return buildProjectSettingsCard({ ...p, noMention: on });
|
|
5874
|
+
});
|
|
5507
5875
|
});
|
|
5508
5876
|
async function resumeFromCard(evt, state, codexThreadId) {
|
|
5509
5877
|
try {
|
|
@@ -5753,8 +6121,6 @@ ${tail}` }, { replyTo: evt.messageId }).catch(() => void 0);
|
|
|
5753
6121
|
if (!evt.mentionedBot) return log.info("comment", "skip", { reason: "not-mentioned" });
|
|
5754
6122
|
if (!SUPPORTED_FILE_TYPES.has(evt.fileType))
|
|
5755
6123
|
return log.info("comment", "skip", { reason: "unsupported-fileType", fileType: evt.fileType });
|
|
5756
|
-
if (!isUserAllowed(cfg, evt.operator.openId))
|
|
5757
|
-
return log.info("comment", "skip", { reason: "not-allowed" });
|
|
5758
6124
|
const resolved = await resolveComment(channel, evt);
|
|
5759
6125
|
if (!resolved) return log.info("comment", "skip", { reason: "no-target-or-empty" });
|
|
5760
6126
|
const { target, ctx } = resolved;
|