@inline-openclaw/inline 0.0.40 → 0.0.42

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.
@@ -20562,6 +20562,8 @@ class InlineSdkClient {
20562
20562
  saveInFlight = null;
20563
20563
  catchUpInFlightByChatId = new Map;
20564
20564
  catchUpRequestedByChatId = new Map;
20565
+ catchUpInFlightBySpaceId = new Map;
20566
+ catchUpRequestedBySpaceId = new Map;
20565
20567
  userCatchUpInFlight = null;
20566
20568
  constructor(options) {
20567
20569
  this.options = options;
@@ -20626,7 +20628,11 @@ class InlineSdkClient {
20626
20628
  this.started = false;
20627
20629
  this.rejectOpen(new Error("closed"));
20628
20630
  this.eventStream.close();
20629
- await Promise.allSettled(this.catchUpInFlightByChatId.values());
20631
+ await Promise.allSettled([
20632
+ ...this.catchUpInFlightByChatId.values(),
20633
+ ...this.catchUpInFlightBySpaceId.values(),
20634
+ ...this.userCatchUpInFlight ? [this.userCatchUpInFlight] : []
20635
+ ]);
20630
20636
  await this.flushStateSave();
20631
20637
  await this.protocol.stopTransport();
20632
20638
  }
@@ -20650,6 +20656,7 @@ class InlineSdkClient {
20650
20656
  version: 1,
20651
20657
  ...this.state.dateCursor != null ? { dateCursor: this.state.dateCursor } : {},
20652
20658
  ...this.state.lastSeqByChatId != null ? { lastSeqByChatId: { ...this.state.lastSeqByChatId } } : {},
20659
+ ...this.state.lastSeqBySpaceId != null ? { lastSeqBySpaceId: { ...this.state.lastSeqBySpaceId } } : {},
20653
20660
  ...this.state.lastUserSeq != null ? { lastUserSeq: this.state.lastUserSeq } : {}
20654
20661
  };
20655
20662
  }
@@ -20670,12 +20677,7 @@ class InlineSdkClient {
20670
20677
  const chat = result.getChat.chat;
20671
20678
  if (!chat)
20672
20679
  throw new Error("getChat: missing chat");
20673
- return {
20674
- chatId: chat.id,
20675
- peer: chat.peerId,
20676
- title: chat.title,
20677
- ...chat.lastMsgId != null ? { lastMsgId: chat.lastMsgId } : {}
20678
- };
20680
+ return { chatId: chat.id, peer: chat.peerId, title: chat.title };
20679
20681
  }
20680
20682
  async getMessages(params) {
20681
20683
  const peerId = this.inputPeerFromTarget(params, "getMessages");
@@ -21004,32 +21006,57 @@ class InlineSdkClient {
21004
21006
  }
21005
21007
  case "clearChatHistory": {
21006
21008
  const payload = update.update.clearChatHistory;
21009
+ if (!payload.target) {
21010
+ this.log.warn?.("Skipping clearChatHistory update without target");
21011
+ return;
21012
+ }
21007
21013
  if (payload.target.oneofKind === "spaceId") {
21014
+ this.bumpSpaceSeq(payload.target.spaceId, seq);
21008
21015
  await this.eventStream.send({
21009
21016
  kind: "space.history.clear",
21010
21017
  spaceId: payload.target.spaceId,
21011
21018
  ...payload.beforeDate != null ? { beforeDate: payload.beforeDate } : {},
21012
21019
  deleteReplyThreads: payload.deleteReplyThreads,
21020
+ deletedChatIds: payload.deletedChatIds,
21021
+ orphanedChatIds: payload.orphanedChatIds,
21022
+ detachedChatIds: payload.detachedChatIds,
21013
21023
  seq,
21014
21024
  date
21015
21025
  });
21016
21026
  return;
21017
21027
  }
21018
21028
  const peerId = payload.target.oneofKind === "peerId" ? payload.target.peerId : undefined;
21019
- const chatId = peerId?.type.oneofKind === "chat" ? peerId.type.chat.chatId : null;
21020
- if (!chatId) {
21021
- this.log.warn?.("Skipping clearChatHistory update without chat peer", peerId);
21029
+ if (peerId?.type.oneofKind === "chat") {
21030
+ const chatId = peerId.type.chat.chatId;
21031
+ this.bumpChatSeq(chatId, seq);
21032
+ await this.eventStream.send({
21033
+ kind: "message.history.clear",
21034
+ chatId,
21035
+ ...payload.beforeDate != null ? { beforeDate: payload.beforeDate } : {},
21036
+ deleteReplyThreads: payload.deleteReplyThreads,
21037
+ deletedChatIds: payload.deletedChatIds,
21038
+ orphanedChatIds: payload.orphanedChatIds,
21039
+ detachedChatIds: payload.detachedChatIds,
21040
+ seq,
21041
+ date
21042
+ });
21022
21043
  return;
21023
21044
  }
21024
- this.bumpChatSeq(chatId, seq);
21025
- await this.eventStream.send({
21026
- kind: "message.history.clear",
21027
- chatId,
21028
- ...payload.beforeDate != null ? { beforeDate: payload.beforeDate } : {},
21029
- deleteReplyThreads: payload.deleteReplyThreads,
21030
- seq,
21031
- date
21032
- });
21045
+ if (peerId?.type.oneofKind === "user") {
21046
+ await this.eventStream.send({
21047
+ kind: "message.history.clear",
21048
+ userId: peerId.type.user.userId,
21049
+ ...payload.beforeDate != null ? { beforeDate: payload.beforeDate } : {},
21050
+ deleteReplyThreads: payload.deleteReplyThreads,
21051
+ deletedChatIds: payload.deletedChatIds,
21052
+ orphanedChatIds: payload.orphanedChatIds,
21053
+ detachedChatIds: payload.detachedChatIds,
21054
+ seq,
21055
+ date
21056
+ });
21057
+ return;
21058
+ }
21059
+ this.log.warn?.("Skipping clearChatHistory update without peer target", peerId);
21033
21060
  return;
21034
21061
  }
21035
21062
  case "updateReaction": {
@@ -21113,6 +21140,7 @@ class InlineSdkClient {
21113
21140
  seq,
21114
21141
  date
21115
21142
  });
21143
+ this.requestCatchUpSpace({ spaceId: payload.spaceId, updateSeq: payload.updateSeq });
21116
21144
  return;
21117
21145
  }
21118
21146
  default:
@@ -21131,6 +21159,18 @@ class InlineSdkClient {
21131
21159
  this.scheduleStateSave();
21132
21160
  }
21133
21161
  }
21162
+ bumpSpaceSeq(spaceId, seq) {
21163
+ if (!Number.isFinite(seq))
21164
+ return;
21165
+ if (!this.state.lastSeqBySpaceId)
21166
+ this.state.lastSeqBySpaceId = {};
21167
+ const key = spaceId.toString();
21168
+ const prev = this.state.lastSeqBySpaceId[key] ?? 0;
21169
+ if (seq > prev) {
21170
+ this.state.lastSeqBySpaceId[key] = seq;
21171
+ this.scheduleStateSave();
21172
+ }
21173
+ }
21134
21174
  shouldSkipUserSeq(seq) {
21135
21175
  if (!Number.isFinite(seq))
21136
21176
  return false;
@@ -21310,6 +21350,112 @@ class InlineSdkClient {
21310
21350
  }
21311
21351
  return false;
21312
21352
  }
21353
+ requestCatchUpSpace(params) {
21354
+ const previous = this.catchUpRequestedBySpaceId.get(params.spaceId);
21355
+ this.catchUpRequestedBySpaceId.set(params.spaceId, {
21356
+ endSeq: Math.max(previous?.endSeq ?? 0, params.updateSeq)
21357
+ });
21358
+ if (this.catchUpInFlightBySpaceId.has(params.spaceId)) {
21359
+ return;
21360
+ }
21361
+ const task = this.drainCatchUpSpace(params.spaceId).catch((error) => {
21362
+ this.catchUpRequestedBySpaceId.delete(params.spaceId);
21363
+ this.log.warn?.("GET_UPDATES space catch-up failed; continuing live delivery", {
21364
+ spaceId: params.spaceId.toString(),
21365
+ error: extractErrorMessage(error)
21366
+ });
21367
+ }).finally(() => {
21368
+ this.catchUpInFlightBySpaceId.delete(params.spaceId);
21369
+ });
21370
+ this.catchUpInFlightBySpaceId.set(params.spaceId, task);
21371
+ }
21372
+ async drainCatchUpSpace(spaceId) {
21373
+ const key = spaceId.toString();
21374
+ while (true) {
21375
+ const request = this.catchUpRequestedBySpaceId.get(spaceId);
21376
+ if (!request)
21377
+ return;
21378
+ const lastSeq = this.state.lastSeqBySpaceId?.[key];
21379
+ const startSeq = lastSeq ?? Math.max(0, request.endSeq - defaultColdStartCatchUpWindow);
21380
+ if (request.endSeq <= startSeq) {
21381
+ this.catchUpRequestedBySpaceId.delete(spaceId);
21382
+ return;
21383
+ }
21384
+ const stop = await this.doCatchUpSpace(spaceId, startSeq, request.endSeq);
21385
+ if (stop) {
21386
+ this.catchUpRequestedBySpaceId.delete(spaceId);
21387
+ return;
21388
+ }
21389
+ const latest = this.catchUpRequestedBySpaceId.get(spaceId);
21390
+ const syncedSeq = this.state.lastSeqBySpaceId?.[key] ?? 0;
21391
+ if (!latest || latest.endSeq <= syncedSeq) {
21392
+ this.catchUpRequestedBySpaceId.delete(spaceId);
21393
+ return;
21394
+ }
21395
+ }
21396
+ }
21397
+ async doCatchUpSpace(spaceId, startSeq, endSeq) {
21398
+ let cursor = startSeq;
21399
+ while (cursor < endSeq) {
21400
+ const result = await this.invoke(Method.GET_UPDATES, {
21401
+ oneofKind: "getUpdates",
21402
+ getUpdates: GetUpdatesInput.create({
21403
+ bucket: UpdateBucket.create({
21404
+ type: {
21405
+ oneofKind: "space",
21406
+ space: {
21407
+ spaceId
21408
+ }
21409
+ }
21410
+ }),
21411
+ startSeq: BigInt(cursor),
21412
+ seqEnd: BigInt(endSeq),
21413
+ totalLimit: defaultCatchUpTotalLimit,
21414
+ limit: defaultCatchUpPageLimit
21415
+ })
21416
+ });
21417
+ const payload = result.getUpdates;
21418
+ if (payload.resultType === GetUpdatesResult_ResultType.TOO_LONG) {
21419
+ this.log.warn?.("GET_UPDATES space too long; fast-forwarding cursor", {
21420
+ spaceId: spaceId.toString(),
21421
+ seq: payload.seq
21422
+ });
21423
+ this.bumpSpaceSeq(spaceId, endSeq);
21424
+ if (payload.date !== 0n) {
21425
+ this.state.dateCursor = payload.date;
21426
+ }
21427
+ this.scheduleStateSave();
21428
+ return true;
21429
+ }
21430
+ const deliveredSeq = Number(payload.seq ?? 0n);
21431
+ if (!Number.isSafeInteger(deliveredSeq)) {
21432
+ this.log.warn?.("GET_UPDATES space returned non-integer seq; aborting catch-up", {
21433
+ spaceId: spaceId.toString()
21434
+ });
21435
+ return true;
21436
+ }
21437
+ this.bumpSpaceSeq(spaceId, deliveredSeq);
21438
+ for (const update of payload.updates) {
21439
+ await this.handleUpdate(update);
21440
+ }
21441
+ if (payload.date !== 0n) {
21442
+ this.state.dateCursor = payload.date;
21443
+ }
21444
+ this.scheduleStateSave();
21445
+ if (payload.final)
21446
+ return true;
21447
+ if (deliveredSeq <= cursor) {
21448
+ this.log.warn?.("GET_UPDATES space made no progress; aborting catch-up", {
21449
+ spaceId: spaceId.toString(),
21450
+ cursor,
21451
+ deliveredSeq
21452
+ });
21453
+ return true;
21454
+ }
21455
+ cursor = deliveredSeq;
21456
+ }
21457
+ return false;
21458
+ }
21313
21459
  peerToInputPeer(peer, chatId) {
21314
21460
  if (!peer) {
21315
21461
  return InputPeer.create({ type: { oneofKind: "chat", chat: { chatId } } });
@@ -21390,6 +21536,7 @@ class InlineSdkClient {
21390
21536
  version: 1,
21391
21537
  ...this.state.dateCursor != null ? { dateCursor: this.state.dateCursor } : {},
21392
21538
  ...this.state.lastSeqByChatId != null ? { lastSeqByChatId: { ...this.state.lastSeqByChatId } } : {},
21539
+ ...this.state.lastSeqBySpaceId != null ? { lastSeqBySpaceId: { ...this.state.lastSeqBySpaceId } } : {},
21393
21540
  ...this.state.lastUserSeq != null ? { lastUserSeq: this.state.lastUserSeq } : {}
21394
21541
  };
21395
21542
  this.saveInFlight = store.save(snapshot).catch((error) => {
@@ -21607,7 +21754,9 @@ var serializeStateV1 = (state) => {
21607
21754
  const json = {
21608
21755
  version: 1,
21609
21756
  ...state.dateCursor != null ? { dateCursor: state.dateCursor.toString() } : {},
21610
- ...state.lastSeqByChatId != null ? { lastSeqByChatId: state.lastSeqByChatId } : {}
21757
+ ...state.lastSeqByChatId != null ? { lastSeqByChatId: state.lastSeqByChatId } : {},
21758
+ ...state.lastSeqBySpaceId != null ? { lastSeqBySpaceId: state.lastSeqBySpaceId } : {},
21759
+ ...state.lastUserSeq != null ? { lastUserSeq: state.lastUserSeq } : {}
21611
21760
  };
21612
21761
  return JSON.stringify(json, null, 2);
21613
21762
  };
@@ -21619,10 +21768,21 @@ var deserializeStateV1 = (raw) => {
21619
21768
  return {
21620
21769
  version: 1,
21621
21770
  ...parsed.dateCursor != null ? { dateCursor: BigInt(parsed.dateCursor) } : {},
21622
- ...parsed.lastSeqByChatId != null ? { lastSeqByChatId: parsed.lastSeqByChatId } : {}
21771
+ ...parsed.lastSeqByChatId != null ? { lastSeqByChatId: parsed.lastSeqByChatId } : {},
21772
+ ...parsed.lastSeqBySpaceId != null ? { lastSeqBySpaceId: parsed.lastSeqBySpaceId } : {},
21773
+ ...parsed.lastUserSeq != null ? { lastUserSeq: parsed.lastUserSeq } : {}
21623
21774
  };
21624
21775
  };
21625
21776
  var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
21777
+ var isSeqRecord = (value) => {
21778
+ if (!isRecord2(value))
21779
+ return false;
21780
+ for (const v of Object.values(value)) {
21781
+ if (typeof v !== "number" || !Number.isFinite(v))
21782
+ return false;
21783
+ }
21784
+ return true;
21785
+ };
21626
21786
  var isStateJsonV1 = (value) => {
21627
21787
  if (!isRecord2(value))
21628
21788
  return false;
@@ -21630,14 +21790,12 @@ var isStateJsonV1 = (value) => {
21630
21790
  return false;
21631
21791
  if (value.dateCursor != null && typeof value.dateCursor !== "string")
21632
21792
  return false;
21633
- if (value.lastSeqByChatId != null) {
21634
- if (!isRecord2(value.lastSeqByChatId))
21635
- return false;
21636
- for (const v of Object.values(value.lastSeqByChatId)) {
21637
- if (typeof v !== "number" || !Number.isFinite(v))
21638
- return false;
21639
- }
21640
- }
21793
+ if (value.lastSeqByChatId != null && !isSeqRecord(value.lastSeqByChatId))
21794
+ return false;
21795
+ if (value.lastSeqBySpaceId != null && !isSeqRecord(value.lastSeqBySpaceId))
21796
+ return false;
21797
+ if (value.lastUserSeq != null && (typeof value.lastUserSeq !== "number" || !Number.isFinite(value.lastUserSeq)))
21798
+ return false;
21641
21799
  return true;
21642
21800
  };
21643
21801
 
@@ -38777,6 +38935,391 @@ async function syncInlineNativeCommands(params) {
38777
38935
  };
38778
38936
  }
38779
38937
 
38938
+ // src/inline/policy.ts
38939
+ function normalizeAccountId2(raw) {
38940
+ return normalizeAccountId(raw);
38941
+ }
38942
+ function resolveInlineGroups(cfg, accountId) {
38943
+ const inline = cfg.channels?.inline;
38944
+ if (!inline)
38945
+ return;
38946
+ const normalized = normalizeAccountId2(accountId);
38947
+ const accounts = inline.accounts ?? {};
38948
+ const accountEntry = accounts[normalized] ?? accounts[Object.keys(accounts).find((key) => key.toLowerCase() === normalized) ?? ""];
38949
+ return accountEntry?.groups ?? inline.groups;
38950
+ }
38951
+ function normalizeGroupId(raw) {
38952
+ const trimmed = raw.trim();
38953
+ if (!trimmed || trimmed === "*")
38954
+ return trimmed;
38955
+ const normalized = normalizeInlineTarget(trimmed);
38956
+ return normalized && /^[0-9]+$/.test(normalized) ? normalized : trimmed;
38957
+ }
38958
+ function resolveGroupConfig(groups, groupId) {
38959
+ if (!groups)
38960
+ return;
38961
+ const normalizedGroupId = normalizeGroupId(groupId ?? "");
38962
+ if (!normalizedGroupId)
38963
+ return;
38964
+ const direct = groups[normalizedGroupId];
38965
+ if (direct)
38966
+ return direct;
38967
+ const lowered = normalizedGroupId.toLowerCase();
38968
+ const matchedKey = Object.keys(groups).find((key) => key !== "*" && normalizeGroupId(key).toLowerCase() === lowered);
38969
+ return matchedKey ? groups[matchedKey] : undefined;
38970
+ }
38971
+ function normalizeSenderKey(raw) {
38972
+ const trimmed = raw.trim();
38973
+ if (!trimmed)
38974
+ return "";
38975
+ const withoutAt = trimmed.startsWith("@") ? trimmed.slice(1) : trimmed;
38976
+ return withoutAt.toLowerCase();
38977
+ }
38978
+ function resolveToolsBySender(params) {
38979
+ const entries = Object.entries(params.toolsBySender ?? {});
38980
+ if (!entries.length)
38981
+ return;
38982
+ const normalizedMap = new Map;
38983
+ let wildcard;
38984
+ for (const [rawKey, policy] of entries) {
38985
+ if (!policy)
38986
+ continue;
38987
+ const key = normalizeSenderKey(rawKey);
38988
+ if (!key)
38989
+ continue;
38990
+ if (key === "*") {
38991
+ wildcard = policy;
38992
+ continue;
38993
+ }
38994
+ if (!normalizedMap.has(key)) {
38995
+ normalizedMap.set(key, policy);
38996
+ }
38997
+ }
38998
+ const candidates = [
38999
+ params.senderId,
39000
+ params.senderE164,
39001
+ params.senderUsername,
39002
+ params.senderName
39003
+ ];
39004
+ for (const candidate of candidates) {
39005
+ const key = normalizeSenderKey(candidate ?? "");
39006
+ if (!key)
39007
+ continue;
39008
+ const matched = normalizedMap.get(key);
39009
+ if (matched)
39010
+ return matched;
39011
+ }
39012
+ return wildcard;
39013
+ }
39014
+ function resolveInlineGroupRequireMention(params) {
39015
+ const groups = resolveInlineGroups(params.cfg, params.accountId);
39016
+ const groupConfig = resolveGroupConfig(groups, params.groupId);
39017
+ const defaultConfig = groups?.["*"];
39018
+ if (typeof groupConfig?.requireMention === "boolean")
39019
+ return groupConfig.requireMention;
39020
+ if (typeof defaultConfig?.requireMention === "boolean")
39021
+ return defaultConfig.requireMention;
39022
+ return params.requireMentionDefault;
39023
+ }
39024
+ function resolveInlineGroupReplyThreadMode(params) {
39025
+ const groups = resolveInlineGroups(params.cfg, params.accountId);
39026
+ const groupConfig = resolveGroupConfig(groups, params.groupId);
39027
+ const defaultConfig = groups?.["*"];
39028
+ return groupConfig?.replyThreadMode ?? defaultConfig?.replyThreadMode ?? params.defaultMode;
39029
+ }
39030
+ function resolveInlineGroupReplyThreadAutoCreateMinMessages(params) {
39031
+ const groups = resolveInlineGroups(params.cfg, params.accountId);
39032
+ const groupConfig = resolveGroupConfig(groups, params.groupId);
39033
+ const defaultConfig = groups?.["*"];
39034
+ return groupConfig?.replyThreadAutoCreateMinMessages ?? defaultConfig?.replyThreadAutoCreateMinMessages ?? params.defaultMinMessages;
39035
+ }
39036
+ function resolveInlineGroupReplyThreadRequireExplicitMention(params) {
39037
+ const groups = resolveInlineGroups(params.cfg, params.accountId);
39038
+ const groupConfig = resolveGroupConfig(groups, params.groupId);
39039
+ const defaultConfig = groups?.["*"];
39040
+ if (typeof groupConfig?.replyThreadRequireExplicitMention === "boolean") {
39041
+ return groupConfig.replyThreadRequireExplicitMention;
39042
+ }
39043
+ if (typeof defaultConfig?.replyThreadRequireExplicitMention === "boolean") {
39044
+ return defaultConfig.replyThreadRequireExplicitMention;
39045
+ }
39046
+ return params.defaultRequireExplicitMention;
39047
+ }
39048
+ function resolveInlineGroupReplyThreadParentHistoryLimit(params) {
39049
+ const groups = resolveInlineGroups(params.cfg, params.accountId);
39050
+ const groupConfig = resolveGroupConfig(groups, params.groupId);
39051
+ const defaultConfig = groups?.["*"];
39052
+ return groupConfig?.replyThreadParentHistoryLimit ?? defaultConfig?.replyThreadParentHistoryLimit ?? params.defaultLimit;
39053
+ }
39054
+ function resolveInlineGroupSystemPrompt(params) {
39055
+ return resolveGroupConfig(params.groups, params.groupId)?.systemPrompt?.trim() || undefined;
39056
+ }
39057
+ function resolveInlineGroupAccessPolicy(params) {
39058
+ const groups = resolveInlineGroups(params.cfg, params.accountId);
39059
+ const hasGroups = Boolean(groups && Object.keys(groups).length > 0);
39060
+ const allowlistEnabled = params.groupPolicy === "allowlist" || hasGroups;
39061
+ const groupConfig = resolveGroupConfig(groups, params.groupId);
39062
+ const defaultConfig = groups?.["*"];
39063
+ const allowAll = allowlistEnabled && Boolean(groups && Object.hasOwn(groups, "*"));
39064
+ const senderFilterBypass = params.groupPolicy === "allowlist" && !hasGroups && params.hasGroupAllowFrom;
39065
+ return {
39066
+ allowlistEnabled,
39067
+ allowed: params.groupPolicy === "disabled" ? false : !allowlistEnabled || allowAll || Boolean(groupConfig) || senderFilterBypass,
39068
+ groupConfig,
39069
+ defaultConfig
39070
+ };
39071
+ }
39072
+ function resolveInlineGroupToolPolicy(params) {
39073
+ const groups = resolveInlineGroups(params.cfg, params.accountId);
39074
+ const groupConfig = resolveGroupConfig(groups, params.groupId);
39075
+ const defaultConfig = groups?.["*"];
39076
+ const groupSenderPolicy = resolveToolsBySender({
39077
+ toolsBySender: groupConfig?.toolsBySender,
39078
+ senderId: params.senderId,
39079
+ senderName: params.senderName,
39080
+ senderUsername: params.senderUsername,
39081
+ senderE164: params.senderE164
39082
+ });
39083
+ if (groupSenderPolicy)
39084
+ return groupSenderPolicy;
39085
+ if (groupConfig?.tools)
39086
+ return groupConfig.tools;
39087
+ const defaultSenderPolicy = resolveToolsBySender({
39088
+ toolsBySender: defaultConfig?.toolsBySender,
39089
+ senderId: params.senderId,
39090
+ senderName: params.senderName,
39091
+ senderUsername: params.senderUsername,
39092
+ senderE164: params.senderE164
39093
+ });
39094
+ if (defaultSenderPolicy)
39095
+ return defaultSenderPolicy;
39096
+ return defaultConfig?.tools;
39097
+ }
39098
+ function resolveInlineGroupAllowFrom(params) {
39099
+ const groups = resolveInlineGroups(params.cfg, params.accountId);
39100
+ const groupConfig = resolveGroupConfig(groups, params.groupId);
39101
+ const defaultConfig = groups?.["*"];
39102
+ if (groupConfig?.allowFrom && groupConfig.allowFrom.length > 0)
39103
+ return groupConfig.allowFrom;
39104
+ if (defaultConfig?.allowFrom && defaultConfig.allowFrom.length > 0)
39105
+ return defaultConfig.allowFrom;
39106
+ return params.accountAllowFrom;
39107
+ }
39108
+
39109
+ // src/inline/threadreply-command.ts
39110
+ var MODE_LABELS = {
39111
+ auto: "auto",
39112
+ thread: "thread",
39113
+ main: "main"
39114
+ };
39115
+ function isRecord3(value) {
39116
+ return typeof value === "object" && value !== null && !Array.isArray(value);
39117
+ }
39118
+ function asInlineConfig(value) {
39119
+ return isRecord3(value) ? value : undefined;
39120
+ }
39121
+ function normalizeMode(raw) {
39122
+ if (typeof raw !== "string")
39123
+ return null;
39124
+ const normalized = raw.trim().toLowerCase();
39125
+ if (normalized === "on" || normalized === "threads")
39126
+ return "thread";
39127
+ if (normalized === "off" || normalized === "parent" || normalized === "parentchat")
39128
+ return "main";
39129
+ if (normalized === "auto" || normalized === "thread" || normalized === "main")
39130
+ return normalized;
39131
+ return null;
39132
+ }
39133
+ function resolveInlineGroupId(ctx) {
39134
+ const raw = ctx.from?.trim() ?? "";
39135
+ if (!/(^|:)chat:/i.test(raw))
39136
+ return null;
39137
+ const normalized = normalizeInlineTarget(raw);
39138
+ return normalized && /^[0-9]+$/.test(normalized) ? normalized : null;
39139
+ }
39140
+ function resolveInlineConfigForAccount(inline, accountId) {
39141
+ const normalized = normalizeAccountId(accountId);
39142
+ const accounts = isRecord3(inline.accounts) ? inline.accounts : undefined;
39143
+ const accountKey = accounts ? Object.keys(accounts).find((key) => normalizeAccountId(key) === normalized) : undefined;
39144
+ if (accountKey && accounts?.[accountKey]) {
39145
+ return accounts[accountKey];
39146
+ }
39147
+ if (normalized !== DEFAULT_ACCOUNT_ID) {
39148
+ return {};
39149
+ }
39150
+ return inline;
39151
+ }
39152
+ function resolveCurrentMode(params) {
39153
+ const inline = asInlineConfig(params.cfg.channels?.inline) ?? {};
39154
+ const accountConfig = resolveInlineConfigForAccount(inline, params.accountId);
39155
+ return resolveInlineGroupReplyThreadMode({
39156
+ cfg: params.cfg,
39157
+ accountId: params.accountId ?? null,
39158
+ groupId: params.groupId,
39159
+ defaultMode: normalizeMode(accountConfig.replyThreadMode) ?? "auto"
39160
+ });
39161
+ }
39162
+ function readExplicitMode(params) {
39163
+ const inline = asInlineConfig(params.cfg.channels?.inline);
39164
+ if (!inline)
39165
+ return null;
39166
+ const accountConfig = resolveInlineConfigForAccount(inline, params.accountId);
39167
+ const group = accountConfig.groups?.[params.groupId];
39168
+ return normalizeMode(group?.replyThreadMode);
39169
+ }
39170
+ function ensureRecordField(parent, key) {
39171
+ const current = parent[key];
39172
+ if (isRecord3(current))
39173
+ return current;
39174
+ const next = {};
39175
+ parent[key] = next;
39176
+ return next;
39177
+ }
39178
+ function resolveMutableInlineConfigForAccount(inline, accountId) {
39179
+ const normalized = normalizeAccountId(accountId);
39180
+ if (normalized === DEFAULT_ACCOUNT_ID) {
39181
+ const accounts2 = isRecord3(inline.accounts) ? inline.accounts : undefined;
39182
+ const defaultKey = accounts2 ? Object.keys(accounts2).find((key) => normalizeAccountId(key) === DEFAULT_ACCOUNT_ID) : undefined;
39183
+ const defaultAccount = defaultKey ? accounts2?.[defaultKey] : undefined;
39184
+ return defaultAccount ?? inline;
39185
+ }
39186
+ const accounts = ensureRecordField(inline, "accounts");
39187
+ const accountKey = Object.keys(accounts).find((key) => normalizeAccountId(key) === normalized) ?? normalized;
39188
+ const account = asInlineConfig(accounts[accountKey]) ?? {};
39189
+ accounts[accountKey] = account;
39190
+ return account;
39191
+ }
39192
+ function setGroupMode(params) {
39193
+ const root = params.draft;
39194
+ const channels = root.channels ?? {};
39195
+ root.channels = channels;
39196
+ const inline = asInlineConfig(channels.inline) ?? {};
39197
+ channels.inline = inline;
39198
+ const accountConfig = resolveMutableInlineConfigForAccount(inline, params.accountId);
39199
+ const groups = ensureRecordField(accountConfig, "groups");
39200
+ const group = isRecord3(groups[params.groupId]) ? groups[params.groupId] : {};
39201
+ groups[params.groupId] = group;
39202
+ if (params.mode === "inherit") {
39203
+ delete group.replyThreadMode;
39204
+ return;
39205
+ }
39206
+ group.replyThreadMode = params.mode;
39207
+ }
39208
+ function buildStatusText(params) {
39209
+ const explicit = readExplicitMode(params);
39210
+ const current = resolveCurrentMode(params);
39211
+ return [
39212
+ `Thread reply mode for chat ${params.groupId}: ${MODE_LABELS[current]}.`,
39213
+ explicit ? `Explicit chat override: ${MODE_LABELS[explicit]}.` : "Explicit chat override: inherit."
39214
+ ].join(`
39215
+ `);
39216
+ }
39217
+ function buildMenuText(params) {
39218
+ return [
39219
+ buildStatusText(params),
39220
+ "",
39221
+ "Choose where automatic replies for this group should go."
39222
+ ].join(`
39223
+ `);
39224
+ }
39225
+ function buildModeButtons() {
39226
+ return {
39227
+ inline: {
39228
+ buttons: [
39229
+ [
39230
+ { text: "Thread", callback_data: "/threadreply thread" },
39231
+ { text: "Main", callback_data: "/threadreply main" },
39232
+ { text: "Auto", callback_data: "/threadreply auto" }
39233
+ ],
39234
+ [{ text: "Inherit", callback_data: "/threadreply inherit" }]
39235
+ ]
39236
+ }
39237
+ };
39238
+ }
39239
+ function normalizeAction(args) {
39240
+ const [first = ""] = args.split(/\s+/).filter(Boolean);
39241
+ const normalized = first.trim().toLowerCase();
39242
+ if (!normalized || normalized === "help" || normalized === "options")
39243
+ return "help";
39244
+ if (normalized === "status" || normalized === "show")
39245
+ return "status";
39246
+ if (normalized === "inherit" || normalized === "default" || normalized === "unset")
39247
+ return "inherit";
39248
+ return normalizeMode(normalized);
39249
+ }
39250
+ async function handleInlineThreadReplyCommand(api2, ctx) {
39251
+ if (!ctx.isAuthorizedSender) {
39252
+ return { text: "This command requires authorization." };
39253
+ }
39254
+ const groupId = resolveInlineGroupId(ctx);
39255
+ if (!groupId) {
39256
+ return { text: "/threadreply is only available in Inline group chats." };
39257
+ }
39258
+ const currentConfig = api2.runtime.config.current();
39259
+ const action = normalizeAction(ctx.args?.trim() ?? "");
39260
+ if (action === "help") {
39261
+ return {
39262
+ text: buildMenuText({
39263
+ cfg: currentConfig,
39264
+ accountId: ctx.accountId,
39265
+ groupId
39266
+ }),
39267
+ channelData: buildModeButtons()
39268
+ };
39269
+ }
39270
+ if (action === "status") {
39271
+ return {
39272
+ text: buildStatusText({
39273
+ cfg: currentConfig,
39274
+ accountId: ctx.accountId,
39275
+ groupId
39276
+ })
39277
+ };
39278
+ }
39279
+ if (!action) {
39280
+ return {
39281
+ text: [
39282
+ "Usage: /threadreply thread|main|auto|inherit|status",
39283
+ "",
39284
+ "- thread: auto-route long parent-chat replies into an Inline reply thread.",
39285
+ "- main: keep automatic replies in the parent chat.",
39286
+ "- auto: use Inline's automatic default behavior for this chat.",
39287
+ "- inherit: remove this chat override and use account/default config."
39288
+ ].join(`
39289
+ `)
39290
+ };
39291
+ }
39292
+ const committed = await api2.runtime.config.mutateConfigFile({
39293
+ afterWrite: { mode: "auto" },
39294
+ mutate: (draft) => {
39295
+ setGroupMode({
39296
+ draft,
39297
+ accountId: ctx.accountId,
39298
+ groupId,
39299
+ mode: action
39300
+ });
39301
+ }
39302
+ });
39303
+ const nextConfig = committed.nextConfig;
39304
+ return {
39305
+ text: buildStatusText({
39306
+ cfg: nextConfig,
39307
+ accountId: ctx.accountId,
39308
+ groupId
39309
+ })
39310
+ };
39311
+ }
39312
+ function createInlineThreadReplyCommand(api2) {
39313
+ return {
39314
+ name: "threadreply",
39315
+ nativeNames: { inline: "threadreply" },
39316
+ description: "Set Inline reply-thread mode for this chat.",
39317
+ channels: ["inline"],
39318
+ acceptsArgs: true,
39319
+ handler: async (ctx) => await handleInlineThreadReplyCommand(api2, ctx)
39320
+ };
39321
+ }
39322
+
38780
39323
  // src/runtime-register-api.ts
38781
39324
  function registerInlinePluginFull(api2) {
38782
39325
  api2.registerTool((ctx) => createInlineMembersTool(ctx), {
@@ -38794,6 +39337,10 @@ function registerInlinePluginFull(api2) {
38794
39337
  api2.registerTool((ctx) => createInlineParentContextTool(ctx), {
38795
39338
  names: ["inline_parent_context"]
38796
39339
  });
39340
+ const registerCommand = api2.registerCommand;
39341
+ if (typeof registerCommand === "function") {
39342
+ registerCommand(createInlineThreadReplyCommand(api2));
39343
+ }
38797
39344
  api2.on("message_sending", (event, ctx) => {
38798
39345
  if (ctx.channelId !== "inline")
38799
39346
  return;
@@ -38821,5 +39368,5 @@ export {
38821
39368
  registerInlinePluginFull
38822
39369
  };
38823
39370
 
38824
- //# debugId=D767F13C52B346E664756E2164756E21
39371
+ //# debugId=D4578A65DC3F320064756E2164756E21
38825
39372
  //# sourceMappingURL=runtime-register-api.js.map