@modesto_ma/dsh-channels 0.5.0-beta.6 → 0.5.0

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/lib/index.js CHANGED
@@ -37,10 +37,16 @@ function decideAccess(subject, config, snapshot) {
37
37
  kind: "allow",
38
38
  reason: "admin"
39
39
  };
40
- if (subject.chatType === "p2p") return {
41
- kind: "deny",
42
- reason: "dm-non-admin"
43
- };
40
+ if (subject.chatType === "p2p") {
41
+ if (config.dmAllowWhitelist && snapshot.users.has(subject.senderId)) return {
42
+ kind: "allow",
43
+ reason: "authorized-user"
44
+ };
45
+ return {
46
+ kind: "deny",
47
+ reason: "dm-non-admin"
48
+ };
49
+ }
44
50
  if (!snapshot.groups.has(subject.chatId)) return {
45
51
  kind: "deny",
46
52
  reason: "group-not-authorized",
@@ -60,6 +66,8 @@ function decideAccess(subject, config, snapshot) {
60
66
  //#region src/access/controller.ts
61
67
  /** Fixed private-chat notice for non-administrators (no model call). */
62
68
  const DM_DENY_TEXT = "非管理员禁用私聊功能哦~如需使用,请在管理员授权的群里 @ 我;或联系管理员把你的 user_id 加入白名单。";
69
+ /** Fixed private-chat notice for non-whitelisted users while `dmAllowWhitelist` is on. */
70
+ const DM_DENY_WHITELIST_TEXT = "你还不在白名单里,暂时不能私聊哦~发送 /userid 查看你的 user_id,请管理员加入白名单后即可使用。";
63
71
  /** Fixed private-chat notice while no administrator is configured. */
64
72
  const DM_UNCONFIGURED_TEXT = "机器人尚未配置管理员。发送 /userid 可查看你的 user_id,交给部署者配置后即可启用。";
65
73
  /** Per-sender cooldown for the repeated private-chat notice (10 s). */
@@ -122,8 +130,9 @@ var AccessController = class {
122
130
  /**
123
131
  * Slash-command admission. Runs before any command card/topic/Session side
124
132
  * effect. `open` mode keeps the legacy behavior; otherwise private chats
125
- * stay administrator-only (with `/userid` as the bootstrap exception) and
126
- * group chats must pass the full admission matrix; the administrator is
133
+ * admit whoever the admission matrix admits (with `/userid` as the
134
+ * bootstrap exception) and group chats must pass the full admission
135
+ * matrix; the administrator is
127
136
  * never constrained by the whitelists, so all of their commands pass even
128
137
  * inside an unauthorized group (`/auth` is the in-conversation grant
129
138
  * entry).
@@ -133,7 +142,7 @@ var AccessController = class {
133
142
  try {
134
143
  if (msg.chatType === "p2p") {
135
144
  if (commandName === "userid") return true;
136
- if (this.isAdmin(msg.senderId)) return true;
145
+ if (this.decide(msg).kind === "allow") return true;
137
146
  await this.noticeDeniedDm(msg);
138
147
  return false;
139
148
  }
@@ -195,7 +204,8 @@ var AccessController = class {
195
204
  const last = this.dmNoticeAt.get(msg.senderId);
196
205
  if (last !== void 0 && now - last < DM_NOTICE_COOLDOWN_MS) return;
197
206
  this.dmNoticeAt.set(msg.senderId, now);
198
- const text = this.config().adminUserId === void 0 ? DM_UNCONFIGURED_TEXT : DM_DENY_TEXT;
207
+ const config = this.config();
208
+ const text = config.adminUserId === void 0 ? DM_UNCONFIGURED_TEXT : config.dmAllowWhitelist ? DM_DENY_WHITELIST_TEXT : DM_DENY_TEXT;
199
209
  await this.sendText(msg.chatId, text, msg.messageId);
200
210
  }
201
211
  /** Best-effort fixed-text send; unavailable channel/failures only warn. */
@@ -400,7 +410,7 @@ function buildUserRequestCard(input) {
400
410
  } else if (input.chatId !== void 0 && input.chatId !== "") elements.push(field("所在群", `\`${input.chatId}\``));
401
411
  elements.push(field("申请时间", formatTime(input.now)));
402
412
  elements.push(divider());
403
- elements.push(note("授权后该用户可在所有已授权群里使用;私聊仍仅管理员可用。"));
413
+ elements.push(note(input.dmAllowWhitelist === true ? "授权后该用户可在所有已授权群里使用,也可以私聊机器人。" : "授权后该用户可在所有已授权群里使用;私聊仍仅管理员可用。"));
404
414
  elements.push(decisionButtons(input.token, "授权用户", "忽略"));
405
415
  return standaloneCard("**🙋 用户授权申请**", elements);
406
416
  }
@@ -733,6 +743,7 @@ var AccessRequests = class {
733
743
  ...groupName === void 0 ? {} : { groupName },
734
744
  ...msg.senderName === void 0 ? {} : { requesterName: msg.senderName },
735
745
  token: record.token,
746
+ dmAllowWhitelist: this.config().dmAllowWhitelist,
736
747
  now
737
748
  }), record);
738
749
  return true;
@@ -1235,8 +1246,8 @@ const accessGroupRecordSchema = z.object({
1235
1246
  });
1236
1247
  /**
1237
1248
  * One authorized user (`user_id`), global across every authorized group.
1238
- * Private chats are administrator-only, so this grant only affects group
1239
- * conversations.
1249
+ * Private chats are administrator-only unless `dmAllowWhitelist` is on, so
1250
+ * by default this grant only affects group conversations.
1240
1251
  */
1241
1252
  const accessUserRecordSchema = z.object({
1242
1253
  /** Feishu `user_id` — also the table key. */
@@ -16269,14 +16280,21 @@ const configSchema = z.object({
16269
16280
  * Admission policy for inbound Feishu traffic.
16270
16281
  *
16271
16282
  * - `guarded` (default): only the configured administrator can talk in
16272
- * private chats, and a group conversation additionally requires the group
16273
- * to be authorized and the sender to be the administrator or an explicitly
16283
+ * private chats (plus whitelisted users when `dmAllowWhitelist` is on),
16284
+ * and a group conversation additionally requires the group to be
16285
+ * authorized and the sender to be the administrator or an explicitly
16274
16286
  * authorized user.
16275
16287
  * - `open`: legacy behavior — any user inside the app's availability scope
16276
16288
  * can start a conversation. Debug/compatibility only; unsafe.
16277
16289
  */
16278
16290
  accessMode: z.enum(["open", "guarded"]).default("guarded"),
16279
16291
  /**
16292
+ * In `guarded` mode, also admit users on the global user whitelist
16293
+ * (`/auth user`) in private chats. Off by default: private chats stay
16294
+ * administrator-only. Each private-chat user already has an own workspace.
16295
+ */
16296
+ dmAllowWhitelist: z.boolean().default(false),
16297
+ /**
16280
16298
  * The unique administrator's Feishu `user_id`. Set it in the Web
16281
16299
  * settings panel (or the profile config). Get it by sending `/userid` to the
16282
16300
  * bot in a private chat. When unset, the Feishu app owner (looked up via
@@ -16436,6 +16454,7 @@ const EDITABLE_KEYS = [
16436
16454
  "feishuTools.topicMessagesTimeoutMs",
16437
16455
  "promptContextTimeoutMs",
16438
16456
  "accessMode",
16457
+ "dmAllowWhitelist",
16439
16458
  "adminUserId",
16440
16459
  "authRequestTtlDays",
16441
16460
  "feishuTools.wikiRead",
@@ -18503,6 +18522,7 @@ var FeishuService = class {
18503
18522
  await this.delivery.standaloneReply(msg, standaloneInfoCard("**🔐 访问授权状态**", [
18504
18523
  `**准入模式**:\`${this.config.accessMode}\``,
18505
18524
  `**管理员**:${this.adminStatusLine()}`,
18525
+ `**私聊**:${this.config.dmAllowWhitelist ? "管理员与白名单用户" : "仅管理员"}`,
18506
18526
  ...msg.chatType === "group" ? [`**本群**:${this.accessStore.hasGroup(msg.chatId) ? "已授权" : "未授权"}(\`${msg.chatId}\`)`] : [],
18507
18527
  `**白名单**:群 ${groups.length} 个 · 用户 ${users.length} 个 · 知识库 ${this.accessStore.wikiUserRecords().length} 个 · 待处理申请 ${pending.length} 个`,
18508
18528
  "群授权:`/auth allow` 或 `/auth revoke`(在目标群内发);用户授权:`/auth user add @用户` 或 `/auth user add <user_id>`;知识库授权:`/auth wiki add @用户`。"
@@ -20060,6 +20080,7 @@ const BOOLEAN_KEYS = /* @__PURE__ */ new Set([
20060
20080
  "welcomeOnboarding",
20061
20081
  "slashCommandPanel",
20062
20082
  "allowPermissionSwitch",
20083
+ "dmAllowWhitelist",
20063
20084
  "acceptAttachments",
20064
20085
  "prefetchImages",
20065
20086
  "feishuTools.attachmentFetch",
@@ -20463,7 +20484,13 @@ const FIELD_META = {
20463
20484
  label: "调试模式",
20464
20485
  group: "access",
20465
20486
  summary: "打开后所有人都能聊,不安全,只在调试时用",
20466
- help: "关闭时(默认):管理员随时可用;非管理员私聊会被拒绝;群聊要同时满足群已授权、发言人在用户白名单里。授权入口有三个:群里 /auth 命令、授权卡、本页。撤销立即生效。"
20487
+ help: "关闭时(默认):管理员随时可用;非管理员私聊会被拒绝(打开「白名单用户可私聊」后白名单用户也可以);群聊要同时满足群已授权、发言人在用户白名单里。授权入口有三个:群里 /auth 命令、授权卡、本页。撤销立即生效。"
20488
+ },
20489
+ dmAllowWhitelist: {
20490
+ label: "白名单用户可私聊",
20491
+ group: "access",
20492
+ summary: "关闭时私聊仅管理员可用",
20493
+ help: "打开后「已授权用户」里的人也可以私聊机器人,各自使用独立的私聊工作区,能力与群聊相同;不在白名单的人仍收到固定提示。撤销用户立即生效。"
20467
20494
  },
20468
20495
  adminUserId: {
20469
20496
  label: "管理员 user_id",
@@ -21617,6 +21644,6 @@ function apply(ctx, config) {
21617
21644
  }, "dsh-channels");
21618
21645
  }
21619
21646
  //#endregion
21620
- export { AUTH_USER_TARGET_ERRORS, AccessController, AccessRequests, AccessStore, ApprovalAnswerer, CARD_MAX_BYTES, CARD_TARGET_BYTES, CATALOG_ROUTE, CHANNEL_COMMAND_NAMES, CONFIG_ROUTE, CREDENTIALS_ROUTE, Config, DM_DENY_TEXT, DM_UNCONFIGURED_TEXT, DSH_CHANNELS_VERSION, EDITABLE_KEYS, EMPTY_TOTALS, FIELD_DESCRIPTORS, FeishuService, HEALTH_DEPENDENCY_NAMES, INTERRUPTION_NOTICE, LOGICAL_EXPORT_FORMAT, LOGICAL_EXPORT_FORMAT_VERSION, MAX_QUESTION_OPTIONS, MAX_TABLES_PER_CARD, OverlayStore, PANEL_CHEVRON_TOKEN, PANEL_COPY, PANEL_ROUTE, PANEL_TITLES, PICK_DIRECTORY_ROUTE, QuestionAnswerer, REASONING_MAX_BYTES, RECONNECT_ROUTE, RESTART_KEYS, RouteOperationQueue, SESSION_HISTORY_DISPLAY_LIMIT, STATUS_ROUTE, SUPPORTED_COMMAND_NAMES, SettingsSurface, TRUNCATION_SUFFIX, TurnStreamer, accessGroupRecordSchema, accessRequestRecordSchema, accessUserRecordSchema, addUsage, appendSessionHistory, apply, applyCatalog, applyProjectionViews, armModelCommand, averageDecodeTokensPerSecond, averageTtftMs, buildApprovalCard, buildApprovalSettledCard, buildCard, buildCommandResultCard, buildCompactComparisonCard, buildGroupInfoCard, buildHealthCard, buildInterruptionCard, buildQuestionCard, buildQuestionSettledCard, buildRenewCard, buildRequestSettledCard, buildSessionHistoryCard, buildSessionStatusCard, buildUserRequestCard, buildWorkDirCard, cacheHitPct, cardJsonBytes, chatRouteKey, commandResultCardKind, compactFailureContext, countFiberStates, createHostCatalog, createLogicalSessionExport, createSettingsDirectoryPicker, decideAccess, defaultOverlayPath, emptyCatalog, ensureWorkspace, expiredRouteRecordSchema, feishuDomain, foldAll, foldEvent, foldHealthSnapshot, foldSessionStats, inflightSnapshotSchema, inject, isAdminUserId, isSameOriginRequest, isSupportedCommand, maskOpenIdTail, measureSessionContext, mergeOverlay, mountSettingsRoutes, name, normalizeCredentialValue, normalizeOverlay, normalizeRouteRecord, normalizeSessionHistory, parseOverlay, parseSlashCommand, pickEditable, processedRecordSchema, querySessionHistory, readProjectionViews, registerChannelCommands, registerModelCommand, registerSettingsRoutes, resolveAuthUserTarget, resolveDshHome, resolveWorkDir, routeRecordSchema, segmentCardContent, serializeLogicalSession, sessionDirOf, sessionHistoryEntrySchema, splitBodyForCard, stagingPathFor, stagingRoot, stripTables, supportedCommandHelp, supportedCommandList, tableBlocks, topicDirFor, topicTokenFor, usageFromBuckets, withDirectoryBrowse, workspacePathFor, workspaceTitleFor, worktreeBranchFor };
21647
+ export { AUTH_USER_TARGET_ERRORS, AccessController, AccessRequests, AccessStore, ApprovalAnswerer, CARD_MAX_BYTES, CARD_TARGET_BYTES, CATALOG_ROUTE, CHANNEL_COMMAND_NAMES, CONFIG_ROUTE, CREDENTIALS_ROUTE, Config, DM_DENY_TEXT, DM_DENY_WHITELIST_TEXT, DM_UNCONFIGURED_TEXT, DSH_CHANNELS_VERSION, EDITABLE_KEYS, EMPTY_TOTALS, FIELD_DESCRIPTORS, FeishuService, HEALTH_DEPENDENCY_NAMES, INTERRUPTION_NOTICE, LOGICAL_EXPORT_FORMAT, LOGICAL_EXPORT_FORMAT_VERSION, MAX_QUESTION_OPTIONS, MAX_TABLES_PER_CARD, OverlayStore, PANEL_CHEVRON_TOKEN, PANEL_COPY, PANEL_ROUTE, PANEL_TITLES, PICK_DIRECTORY_ROUTE, QuestionAnswerer, REASONING_MAX_BYTES, RECONNECT_ROUTE, RESTART_KEYS, RouteOperationQueue, SESSION_HISTORY_DISPLAY_LIMIT, STATUS_ROUTE, SUPPORTED_COMMAND_NAMES, SettingsSurface, TRUNCATION_SUFFIX, TurnStreamer, accessGroupRecordSchema, accessRequestRecordSchema, accessUserRecordSchema, addUsage, appendSessionHistory, apply, applyCatalog, applyProjectionViews, armModelCommand, averageDecodeTokensPerSecond, averageTtftMs, buildApprovalCard, buildApprovalSettledCard, buildCard, buildCommandResultCard, buildCompactComparisonCard, buildGroupInfoCard, buildHealthCard, buildInterruptionCard, buildQuestionCard, buildQuestionSettledCard, buildRenewCard, buildRequestSettledCard, buildSessionHistoryCard, buildSessionStatusCard, buildUserRequestCard, buildWorkDirCard, cacheHitPct, cardJsonBytes, chatRouteKey, commandResultCardKind, compactFailureContext, countFiberStates, createHostCatalog, createLogicalSessionExport, createSettingsDirectoryPicker, decideAccess, defaultOverlayPath, emptyCatalog, ensureWorkspace, expiredRouteRecordSchema, feishuDomain, foldAll, foldEvent, foldHealthSnapshot, foldSessionStats, inflightSnapshotSchema, inject, isAdminUserId, isSameOriginRequest, isSupportedCommand, maskOpenIdTail, measureSessionContext, mergeOverlay, mountSettingsRoutes, name, normalizeCredentialValue, normalizeOverlay, normalizeRouteRecord, normalizeSessionHistory, parseOverlay, parseSlashCommand, pickEditable, processedRecordSchema, querySessionHistory, readProjectionViews, registerChannelCommands, registerModelCommand, registerSettingsRoutes, resolveAuthUserTarget, resolveDshHome, resolveWorkDir, routeRecordSchema, segmentCardContent, serializeLogicalSession, sessionDirOf, sessionHistoryEntrySchema, splitBodyForCard, stagingPathFor, stagingRoot, stripTables, supportedCommandHelp, supportedCommandList, tableBlocks, topicDirFor, topicTokenFor, usageFromBuckets, withDirectoryBrowse, workspacePathFor, workspaceTitleFor, worktreeBranchFor };
21621
21648
 
21622
21649
  //# sourceMappingURL=index.js.map