@inline-openclaw/inline 0.0.41 → 0.0.43

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
 
@@ -38202,6 +38360,7 @@ var INLINE_FORMATTING_RULES = [
38202
38360
  "Prefer bullet lists over markdown tables.",
38203
38361
  "If a table is necessary, render it inside a fenced code block.",
38204
38362
  "Use plain URLs or markdown links; do not wrap bare URLs in inline code or backticks.",
38363
+ "Mention Inline users with markdown links like [@FirstName](inline://user?id=123); use inline://user?username=username only when the user id is unavailable.",
38205
38364
  "Use inline code only for actual code, commands, file paths, env vars, or identifiers."
38206
38365
  ];
38207
38366
  var INLINE_COPY_REPLACEMENTS = [
@@ -38777,6 +38936,482 @@ async function syncInlineNativeCommands(params) {
38777
38936
  };
38778
38937
  }
38779
38938
 
38939
+ // src/inline/policy.ts
38940
+ function normalizeAccountId2(raw) {
38941
+ return normalizeAccountId(raw);
38942
+ }
38943
+ function resolveInlineGroups(cfg, accountId) {
38944
+ const inline = cfg.channels?.inline;
38945
+ if (!inline)
38946
+ return;
38947
+ const normalized = normalizeAccountId2(accountId);
38948
+ const accounts = inline.accounts ?? {};
38949
+ const accountEntry = accounts[normalized] ?? accounts[Object.keys(accounts).find((key) => key.toLowerCase() === normalized) ?? ""];
38950
+ return accountEntry?.groups ?? inline.groups;
38951
+ }
38952
+ function normalizeGroupId(raw) {
38953
+ const trimmed = raw.trim();
38954
+ if (!trimmed || trimmed === "*")
38955
+ return trimmed;
38956
+ const normalized = normalizeInlineTarget(trimmed);
38957
+ return normalized && /^[0-9]+$/.test(normalized) ? normalized : trimmed;
38958
+ }
38959
+ function resolveGroupConfig(groups, groupId) {
38960
+ if (!groups)
38961
+ return;
38962
+ const normalizedGroupId = normalizeGroupId(groupId ?? "");
38963
+ if (!normalizedGroupId)
38964
+ return;
38965
+ const direct = groups[normalizedGroupId];
38966
+ if (direct)
38967
+ return direct;
38968
+ const lowered = normalizedGroupId.toLowerCase();
38969
+ const matchedKey = Object.keys(groups).find((key) => key !== "*" && normalizeGroupId(key).toLowerCase() === lowered);
38970
+ return matchedKey ? groups[matchedKey] : undefined;
38971
+ }
38972
+ function normalizeSenderKey(raw) {
38973
+ const trimmed = raw.trim();
38974
+ if (!trimmed)
38975
+ return "";
38976
+ const withoutAt = trimmed.startsWith("@") ? trimmed.slice(1) : trimmed;
38977
+ return withoutAt.toLowerCase();
38978
+ }
38979
+ function resolveToolsBySender(params) {
38980
+ const entries = Object.entries(params.toolsBySender ?? {});
38981
+ if (!entries.length)
38982
+ return;
38983
+ const normalizedMap = new Map;
38984
+ let wildcard;
38985
+ for (const [rawKey, policy] of entries) {
38986
+ if (!policy)
38987
+ continue;
38988
+ const key = normalizeSenderKey(rawKey);
38989
+ if (!key)
38990
+ continue;
38991
+ if (key === "*") {
38992
+ wildcard = policy;
38993
+ continue;
38994
+ }
38995
+ if (!normalizedMap.has(key)) {
38996
+ normalizedMap.set(key, policy);
38997
+ }
38998
+ }
38999
+ const candidates = [
39000
+ params.senderId,
39001
+ params.senderE164,
39002
+ params.senderUsername,
39003
+ params.senderName
39004
+ ];
39005
+ for (const candidate of candidates) {
39006
+ const key = normalizeSenderKey(candidate ?? "");
39007
+ if (!key)
39008
+ continue;
39009
+ const matched = normalizedMap.get(key);
39010
+ if (matched)
39011
+ return matched;
39012
+ }
39013
+ return wildcard;
39014
+ }
39015
+ function resolveInlineGroupRequireMention(params) {
39016
+ const groups = resolveInlineGroups(params.cfg, params.accountId);
39017
+ const groupConfig = resolveGroupConfig(groups, params.groupId);
39018
+ const defaultConfig = groups?.["*"];
39019
+ if (typeof groupConfig?.requireMention === "boolean")
39020
+ return groupConfig.requireMention;
39021
+ if (typeof defaultConfig?.requireMention === "boolean")
39022
+ return defaultConfig.requireMention;
39023
+ return params.requireMentionDefault;
39024
+ }
39025
+ function resolveInlineGroupReplyThreadMode(params) {
39026
+ const groups = resolveInlineGroups(params.cfg, params.accountId);
39027
+ const groupConfig = resolveGroupConfig(groups, params.groupId);
39028
+ const defaultConfig = groups?.["*"];
39029
+ return groupConfig?.replyThreadMode ?? defaultConfig?.replyThreadMode ?? params.defaultMode;
39030
+ }
39031
+ function resolveInlineGroupReplyThreadAutoCreateMinMessages(params) {
39032
+ const groups = resolveInlineGroups(params.cfg, params.accountId);
39033
+ const groupConfig = resolveGroupConfig(groups, params.groupId);
39034
+ const defaultConfig = groups?.["*"];
39035
+ return groupConfig?.replyThreadAutoCreateMinMessages ?? defaultConfig?.replyThreadAutoCreateMinMessages ?? params.defaultMinMessages;
39036
+ }
39037
+ function resolveInlineGroupReplyThreadRequireExplicitMention(params) {
39038
+ const groups = resolveInlineGroups(params.cfg, params.accountId);
39039
+ const groupConfig = resolveGroupConfig(groups, params.groupId);
39040
+ const defaultConfig = groups?.["*"];
39041
+ if (typeof groupConfig?.replyThreadRequireExplicitMention === "boolean") {
39042
+ return groupConfig.replyThreadRequireExplicitMention;
39043
+ }
39044
+ if (typeof defaultConfig?.replyThreadRequireExplicitMention === "boolean") {
39045
+ return defaultConfig.replyThreadRequireExplicitMention;
39046
+ }
39047
+ return params.defaultRequireExplicitMention;
39048
+ }
39049
+ function resolveInlineGroupReplyThreadParentHistoryLimit(params) {
39050
+ const groups = resolveInlineGroups(params.cfg, params.accountId);
39051
+ const groupConfig = resolveGroupConfig(groups, params.groupId);
39052
+ const defaultConfig = groups?.["*"];
39053
+ return groupConfig?.replyThreadParentHistoryLimit ?? defaultConfig?.replyThreadParentHistoryLimit ?? params.defaultLimit;
39054
+ }
39055
+ function resolveInlineGroupSystemPrompt(params) {
39056
+ return resolveGroupConfig(params.groups, params.groupId)?.systemPrompt?.trim() || undefined;
39057
+ }
39058
+ function resolveInlineGroupAccessPolicy(params) {
39059
+ const groups = resolveInlineGroups(params.cfg, params.accountId);
39060
+ const hasGroups = Boolean(groups && Object.keys(groups).length > 0);
39061
+ const allowlistEnabled = params.groupPolicy === "allowlist" || hasGroups;
39062
+ const groupConfig = resolveGroupConfig(groups, params.groupId);
39063
+ const defaultConfig = groups?.["*"];
39064
+ const allowAll = allowlistEnabled && Boolean(groups && Object.hasOwn(groups, "*"));
39065
+ const senderFilterBypass = params.groupPolicy === "allowlist" && !hasGroups && params.hasGroupAllowFrom;
39066
+ return {
39067
+ allowlistEnabled,
39068
+ allowed: params.groupPolicy === "disabled" ? false : !allowlistEnabled || allowAll || Boolean(groupConfig) || senderFilterBypass,
39069
+ groupConfig,
39070
+ defaultConfig
39071
+ };
39072
+ }
39073
+ function resolveInlineGroupToolPolicy(params) {
39074
+ const groups = resolveInlineGroups(params.cfg, params.accountId);
39075
+ const groupConfig = resolveGroupConfig(groups, params.groupId);
39076
+ const defaultConfig = groups?.["*"];
39077
+ const groupSenderPolicy = resolveToolsBySender({
39078
+ toolsBySender: groupConfig?.toolsBySender,
39079
+ senderId: params.senderId,
39080
+ senderName: params.senderName,
39081
+ senderUsername: params.senderUsername,
39082
+ senderE164: params.senderE164
39083
+ });
39084
+ if (groupSenderPolicy)
39085
+ return groupSenderPolicy;
39086
+ if (groupConfig?.tools)
39087
+ return groupConfig.tools;
39088
+ const defaultSenderPolicy = resolveToolsBySender({
39089
+ toolsBySender: defaultConfig?.toolsBySender,
39090
+ senderId: params.senderId,
39091
+ senderName: params.senderName,
39092
+ senderUsername: params.senderUsername,
39093
+ senderE164: params.senderE164
39094
+ });
39095
+ if (defaultSenderPolicy)
39096
+ return defaultSenderPolicy;
39097
+ return defaultConfig?.tools;
39098
+ }
39099
+ function resolveInlineGroupAllowFrom(params) {
39100
+ const groups = resolveInlineGroups(params.cfg, params.accountId);
39101
+ const groupConfig = resolveGroupConfig(groups, params.groupId);
39102
+ const defaultConfig = groups?.["*"];
39103
+ if (groupConfig?.allowFrom && groupConfig.allowFrom.length > 0)
39104
+ return groupConfig.allowFrom;
39105
+ if (defaultConfig?.allowFrom && defaultConfig.allowFrom.length > 0)
39106
+ return defaultConfig.allowFrom;
39107
+ return params.accountAllowFrom;
39108
+ }
39109
+
39110
+ // src/inline/threadreply-command.ts
39111
+ var MODE_LABELS = {
39112
+ auto: "auto",
39113
+ thread: "thread",
39114
+ main: "main"
39115
+ };
39116
+ var DEFAULT_REPLY_THREAD_AUTO_CREATE_MIN_MESSAGES = 50;
39117
+ function isRecord3(value) {
39118
+ return typeof value === "object" && value !== null && !Array.isArray(value);
39119
+ }
39120
+ function asInlineConfig(value) {
39121
+ return isRecord3(value) ? value : undefined;
39122
+ }
39123
+ function normalizeMode(raw) {
39124
+ if (typeof raw !== "string")
39125
+ return null;
39126
+ const normalized = raw.trim().toLowerCase();
39127
+ if (normalized === "on" || normalized === "threads")
39128
+ return "thread";
39129
+ if (normalized === "off" || normalized === "parent" || normalized === "parentchat")
39130
+ return "main";
39131
+ if (normalized === "auto" || normalized === "thread" || normalized === "main")
39132
+ return normalized;
39133
+ return null;
39134
+ }
39135
+ function normalizeMin(raw) {
39136
+ if (typeof raw !== "number")
39137
+ return null;
39138
+ if (!Number.isInteger(raw) || raw < 0)
39139
+ return null;
39140
+ return raw;
39141
+ }
39142
+ function parseMinArg(raw) {
39143
+ const value = raw?.trim().toLowerCase();
39144
+ if (!value)
39145
+ return null;
39146
+ if (value === "inherit" || value === "default" || value === "unset")
39147
+ return "inherit";
39148
+ if (!/^\d+$/.test(value))
39149
+ return null;
39150
+ const parsed = Number(value);
39151
+ return Number.isSafeInteger(parsed) ? parsed : null;
39152
+ }
39153
+ function resolveInlineGroupId(ctx) {
39154
+ const raw = ctx.from?.trim() ?? "";
39155
+ if (!/(^|:)chat:/i.test(raw))
39156
+ return null;
39157
+ const normalized = normalizeInlineTarget(raw);
39158
+ return normalized && /^[0-9]+$/.test(normalized) ? normalized : null;
39159
+ }
39160
+ function resolveInlineConfigForAccount(inline, accountId) {
39161
+ const normalized = normalizeAccountId(accountId);
39162
+ const accounts = isRecord3(inline.accounts) ? inline.accounts : undefined;
39163
+ const accountKey = accounts ? Object.keys(accounts).find((key) => normalizeAccountId(key) === normalized) : undefined;
39164
+ if (accountKey && accounts?.[accountKey]) {
39165
+ return accounts[accountKey];
39166
+ }
39167
+ if (normalized !== DEFAULT_ACCOUNT_ID) {
39168
+ return {};
39169
+ }
39170
+ return inline;
39171
+ }
39172
+ function resolveCurrentMode(params) {
39173
+ const inline = asInlineConfig(params.cfg.channels?.inline) ?? {};
39174
+ const accountConfig = resolveInlineConfigForAccount(inline, params.accountId);
39175
+ return resolveInlineGroupReplyThreadMode({
39176
+ cfg: params.cfg,
39177
+ accountId: params.accountId ?? null,
39178
+ groupId: params.groupId,
39179
+ defaultMode: normalizeMode(accountConfig.replyThreadMode) ?? "auto"
39180
+ });
39181
+ }
39182
+ function resolveCurrentMinMessages(params) {
39183
+ const inline = asInlineConfig(params.cfg.channels?.inline) ?? {};
39184
+ const accountConfig = resolveInlineConfigForAccount(inline, params.accountId);
39185
+ return resolveInlineGroupReplyThreadAutoCreateMinMessages({
39186
+ cfg: params.cfg,
39187
+ accountId: params.accountId ?? null,
39188
+ groupId: params.groupId,
39189
+ defaultMinMessages: normalizeMin(accountConfig.replyThreadAutoCreateMinMessages) ?? DEFAULT_REPLY_THREAD_AUTO_CREATE_MIN_MESSAGES
39190
+ });
39191
+ }
39192
+ function readExplicitMode(params) {
39193
+ const inline = asInlineConfig(params.cfg.channels?.inline);
39194
+ if (!inline)
39195
+ return null;
39196
+ const accountConfig = resolveInlineConfigForAccount(inline, params.accountId);
39197
+ const group = accountConfig.groups?.[params.groupId];
39198
+ return normalizeMode(group?.replyThreadMode);
39199
+ }
39200
+ function readExplicitMinMessages(params) {
39201
+ const inline = asInlineConfig(params.cfg.channels?.inline);
39202
+ if (!inline)
39203
+ return null;
39204
+ const accountConfig = resolveInlineConfigForAccount(inline, params.accountId);
39205
+ const group = accountConfig.groups?.[params.groupId];
39206
+ return normalizeMin(group?.replyThreadAutoCreateMinMessages);
39207
+ }
39208
+ function ensureRecordField(parent, key) {
39209
+ const current = parent[key];
39210
+ if (isRecord3(current))
39211
+ return current;
39212
+ const next = {};
39213
+ parent[key] = next;
39214
+ return next;
39215
+ }
39216
+ function resolveMutableInlineConfigForAccount(inline, accountId) {
39217
+ const normalized = normalizeAccountId(accountId);
39218
+ if (normalized === DEFAULT_ACCOUNT_ID) {
39219
+ const accounts2 = isRecord3(inline.accounts) ? inline.accounts : undefined;
39220
+ const defaultKey = accounts2 ? Object.keys(accounts2).find((key) => normalizeAccountId(key) === DEFAULT_ACCOUNT_ID) : undefined;
39221
+ const defaultAccount = defaultKey ? accounts2?.[defaultKey] : undefined;
39222
+ return defaultAccount ?? inline;
39223
+ }
39224
+ const accounts = ensureRecordField(inline, "accounts");
39225
+ const accountKey = Object.keys(accounts).find((key) => normalizeAccountId(key) === normalized) ?? normalized;
39226
+ const account = asInlineConfig(accounts[accountKey]) ?? {};
39227
+ accounts[accountKey] = account;
39228
+ return account;
39229
+ }
39230
+ function setGroupMode(params) {
39231
+ const root = params.draft;
39232
+ const channels = root.channels ?? {};
39233
+ root.channels = channels;
39234
+ const inline = asInlineConfig(channels.inline) ?? {};
39235
+ channels.inline = inline;
39236
+ const accountConfig = resolveMutableInlineConfigForAccount(inline, params.accountId);
39237
+ const groups = ensureRecordField(accountConfig, "groups");
39238
+ const group = isRecord3(groups[params.groupId]) ? groups[params.groupId] : {};
39239
+ groups[params.groupId] = group;
39240
+ if (params.mode === "inherit") {
39241
+ delete group.replyThreadMode;
39242
+ return;
39243
+ }
39244
+ group.replyThreadMode = params.mode;
39245
+ }
39246
+ function setGroupMinMessages(params) {
39247
+ const root = params.draft;
39248
+ const channels = root.channels ?? {};
39249
+ root.channels = channels;
39250
+ const inline = asInlineConfig(channels.inline) ?? {};
39251
+ channels.inline = inline;
39252
+ const accountConfig = resolveMutableInlineConfigForAccount(inline, params.accountId);
39253
+ const groups = ensureRecordField(accountConfig, "groups");
39254
+ const group = isRecord3(groups[params.groupId]) ? groups[params.groupId] : {};
39255
+ groups[params.groupId] = group;
39256
+ if (params.minMessages === "inherit") {
39257
+ delete group.replyThreadAutoCreateMinMessages;
39258
+ return;
39259
+ }
39260
+ group.replyThreadAutoCreateMinMessages = params.minMessages;
39261
+ }
39262
+ function buildStatusText(params) {
39263
+ const explicit = readExplicitMode(params);
39264
+ const current = resolveCurrentMode(params);
39265
+ const explicitMin = readExplicitMinMessages(params);
39266
+ const currentMin = resolveCurrentMinMessages(params);
39267
+ return [
39268
+ `Thread reply mode for chat ${params.groupId}: ${MODE_LABELS[current]}.`,
39269
+ explicit ? `Explicit chat override: ${MODE_LABELS[explicit]}.` : "Explicit chat override: inherit.",
39270
+ `Auto-create minimum messages: ${currentMin}.`,
39271
+ explicitMin != null ? `Explicit minimum override: ${explicitMin}.` : "Explicit minimum override: inherit."
39272
+ ].join(`
39273
+ `);
39274
+ }
39275
+ function buildMenuText(params) {
39276
+ return [
39277
+ buildStatusText(params),
39278
+ "",
39279
+ "Choose where automatic replies for this group should go."
39280
+ ].join(`
39281
+ `);
39282
+ }
39283
+ function buildModeButtons() {
39284
+ return {
39285
+ inline: {
39286
+ buttons: [
39287
+ [
39288
+ { text: "Thread", callback_data: "/threadreply thread" },
39289
+ { text: "Main", callback_data: "/threadreply main" },
39290
+ { text: "Auto", callback_data: "/threadreply auto" }
39291
+ ],
39292
+ [{ text: "Inherit Mode", callback_data: "/threadreply inherit" }],
39293
+ [
39294
+ { text: "Min 0", callback_data: "/threadreply min 0" },
39295
+ { text: "Min 50", callback_data: "/threadreply min 50" },
39296
+ { text: "Inherit Min", callback_data: "/threadreply min inherit" }
39297
+ ]
39298
+ ]
39299
+ }
39300
+ };
39301
+ }
39302
+ function normalizeAction(args) {
39303
+ const [first = ""] = args.split(/\s+/).filter(Boolean);
39304
+ const normalized = first.trim().toLowerCase();
39305
+ if (!normalized || normalized === "help" || normalized === "options")
39306
+ return "help";
39307
+ if (normalized === "status" || normalized === "show")
39308
+ return "status";
39309
+ if (normalized === "inherit" || normalized === "default" || normalized === "unset")
39310
+ return "inherit";
39311
+ return normalizeMode(normalized);
39312
+ }
39313
+ async function handleInlineThreadReplyCommand(api2, ctx) {
39314
+ if (!ctx.isAuthorizedSender) {
39315
+ return { text: "This command requires authorization." };
39316
+ }
39317
+ const groupId = resolveInlineGroupId(ctx);
39318
+ if (!groupId) {
39319
+ return { text: "/threadreply is only available in Inline group chats." };
39320
+ }
39321
+ const currentConfig = api2.runtime.config.current();
39322
+ const args = ctx.args?.trim() ?? "";
39323
+ const [first = "", second, ...rest] = args.split(/\s+/).filter(Boolean);
39324
+ if (["min", "minimum", "threshold", "limit"].includes(first.trim().toLowerCase())) {
39325
+ const minMessages = parseMinArg(second);
39326
+ if (minMessages == null || rest.length > 0) {
39327
+ return { text: "Usage: /threadreply min <0-or-greater>|inherit" };
39328
+ }
39329
+ const committed2 = await api2.runtime.config.mutateConfigFile({
39330
+ afterWrite: { mode: "auto" },
39331
+ mutate: (draft) => {
39332
+ setGroupMinMessages({
39333
+ draft,
39334
+ accountId: ctx.accountId,
39335
+ groupId,
39336
+ minMessages
39337
+ });
39338
+ }
39339
+ });
39340
+ const nextConfig2 = committed2.nextConfig;
39341
+ return {
39342
+ text: buildStatusText({
39343
+ cfg: nextConfig2,
39344
+ accountId: ctx.accountId,
39345
+ groupId
39346
+ })
39347
+ };
39348
+ }
39349
+ const action = normalizeAction(args);
39350
+ if (action === "help") {
39351
+ return {
39352
+ text: buildMenuText({
39353
+ cfg: currentConfig,
39354
+ accountId: ctx.accountId,
39355
+ groupId
39356
+ }),
39357
+ channelData: buildModeButtons()
39358
+ };
39359
+ }
39360
+ if (action === "status") {
39361
+ return {
39362
+ text: buildStatusText({
39363
+ cfg: currentConfig,
39364
+ accountId: ctx.accountId,
39365
+ groupId
39366
+ })
39367
+ };
39368
+ }
39369
+ if (!action) {
39370
+ return {
39371
+ text: [
39372
+ "Usage: /threadreply thread|main|auto|inherit|status",
39373
+ " /threadreply min <0-or-greater>|inherit",
39374
+ "",
39375
+ "- thread: auto-route parent-chat replies into per-message Inline reply threads once the minimum is reached.",
39376
+ "- main: keep automatic replies in the parent chat.",
39377
+ "- auto: use Inline's automatic default behavior for this chat.",
39378
+ "- inherit: remove this chat override and use account/default config.",
39379
+ "- min: set how many parent-chat messages must exist before automatic thread creation."
39380
+ ].join(`
39381
+ `)
39382
+ };
39383
+ }
39384
+ const committed = await api2.runtime.config.mutateConfigFile({
39385
+ afterWrite: { mode: "auto" },
39386
+ mutate: (draft) => {
39387
+ setGroupMode({
39388
+ draft,
39389
+ accountId: ctx.accountId,
39390
+ groupId,
39391
+ mode: action
39392
+ });
39393
+ }
39394
+ });
39395
+ const nextConfig = committed.nextConfig;
39396
+ return {
39397
+ text: buildStatusText({
39398
+ cfg: nextConfig,
39399
+ accountId: ctx.accountId,
39400
+ groupId
39401
+ })
39402
+ };
39403
+ }
39404
+ function createInlineThreadReplyCommand(api2) {
39405
+ return {
39406
+ name: "threadreply",
39407
+ nativeNames: { inline: "threadreply" },
39408
+ description: "Set Inline reply-thread mode for this chat.",
39409
+ channels: ["inline"],
39410
+ acceptsArgs: true,
39411
+ handler: async (ctx) => await handleInlineThreadReplyCommand(api2, ctx)
39412
+ };
39413
+ }
39414
+
38780
39415
  // src/runtime-register-api.ts
38781
39416
  function registerInlinePluginFull(api2) {
38782
39417
  api2.registerTool((ctx) => createInlineMembersTool(ctx), {
@@ -38794,6 +39429,10 @@ function registerInlinePluginFull(api2) {
38794
39429
  api2.registerTool((ctx) => createInlineParentContextTool(ctx), {
38795
39430
  names: ["inline_parent_context"]
38796
39431
  });
39432
+ const registerCommand = api2.registerCommand;
39433
+ if (typeof registerCommand === "function") {
39434
+ registerCommand(createInlineThreadReplyCommand(api2));
39435
+ }
38797
39436
  api2.on("message_sending", (event, ctx) => {
38798
39437
  if (ctx.channelId !== "inline")
38799
39438
  return;
@@ -38821,5 +39460,5 @@ export {
38821
39460
  registerInlinePluginFull
38822
39461
  };
38823
39462
 
38824
- //# debugId=D767F13C52B346E664756E2164756E21
39463
+ //# debugId=6281D0C5544F91C564756E2164756E21
38825
39464
  //# sourceMappingURL=runtime-register-api.js.map