@openclaw/matrix 2026.7.2-beta.7 → 2026.8.1-beta.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.
Files changed (83) hide show
  1. package/dist/{account-selection-kqquRzCf.js → account-selection-CWuhuFn1.js} +7 -8
  2. package/dist/{accounts-DfngqebB.js → accounts-BCzyubQt.js} +3 -3
  3. package/dist/api.js +7 -10
  4. package/dist/{approval-handler.runtime-DSeaIsGa.js → approval-handler.runtime-CJXCUdRg.js} +5 -5
  5. package/dist/{approval-ids-BdJGPAJT.js → approval-ids-7rf7etWE.js} +1 -1
  6. package/dist/{approval-reaction-auth-BjOpELxu.js → approval-reaction-auth-wBwbEDpZ.js} +2 -2
  7. package/dist/{approval-reactions-D-BxBK_L.js → approval-reactions-tXh9KYrW.js} +2 -8
  8. package/dist/auth-presence.js +2 -2
  9. package/dist/{channel-vj788dNZ.js → channel-VSrHgTON.js} +156 -136
  10. package/dist/channel-plugin-api.js +1 -1
  11. package/dist/{channel.runtime-CLoF2S9T.js → channel.runtime-pOOL0uT_.js} +70 -56
  12. package/dist/{config-schema-Djxw3C6b.js → channel.setup-PpxRP9Du.js} +50 -3
  13. package/dist/{cli-DMqfDE-q.js → cli-CkTfKC_c.js} +16 -16
  14. package/dist/{cli-metadata-C7D53SND.js → cli-metadata-B1d1aGM5.js} +1 -1
  15. package/dist/cli-metadata.js +1 -1
  16. package/dist/client-CeGw0G5S.js +784 -0
  17. package/dist/{client-bootstrap-XsIkHNt0.js → client-bootstrap-BFwT_2VT.js} +25 -61
  18. package/dist/{client-6eRENr7k.js → client-sJesKQmp.js} +4 -4
  19. package/dist/client-support-DLj4vDeu.js +93 -0
  20. package/dist/config-update-Bor_Pjsv.js +150 -0
  21. package/dist/contract-api.js +2 -2
  22. package/dist/{credentials-W2EmwRhu.js → credentials-BdAaWuiR.js} +2 -1
  23. package/dist/credentials-read-B37cQknZ.js +51 -0
  24. package/dist/credentials-state-B3cuUFwZ.js +27 -0
  25. package/dist/{credentials-write.runtime-Be9zNSUw.js → credentials-write.runtime-nAV2-5uR.js} +1 -1
  26. package/dist/{crypto-runtime-D9_6J5tZ.js → crypto-runtime-Bnz3zEcS.js} +55 -32
  27. package/dist/direct-room-RinHjtqX.js +71 -0
  28. package/dist/{directory-live-C8dVBiCc.js → directory-live-Bvg2wAnR.js} +1 -2
  29. package/dist/{doctor-CM8ijNpW.js → doctor-EWf9CDso.js} +2 -2
  30. package/dist/{doctor-contract-BMSJkkAE.js → doctor-contract-DEt4O4Zt.js} +2 -3
  31. package/dist/doctor-contract-api.js +202 -90
  32. package/dist/{draft-stream-CtvOXq0Z.js → draft-stream-BRi7PRRS.js} +20 -23
  33. package/dist/{encryption-guidance-CbEFe38F.js → encryption-guidance-DmLY8NiO.js} +1 -1
  34. package/dist/{env-auth-CQsYbz-p.js → env-auth-MVS-Vv41.js} +4 -3
  35. package/dist/{env-vars-B0NxQnPk.js → env-vars-dGqak9dN.js} +1 -1
  36. package/dist/{errors-C47hvAF8.js → errors-DKVS3_DO.js} +2 -5
  37. package/dist/{file-sync-store-DiiFsayX.js → file-sync-store-DjskBX2o.js} +24 -3
  38. package/dist/helper-api.js +2 -2
  39. package/dist/{idb-persistence-B6x7dMsF.js → idb-persistence-BM0P27Zg.js} +3 -2
  40. package/dist/{inbound-dedupe-CaBLblef.js → inbound-dedupe-RvSLqdsz.js} +2 -2
  41. package/dist/index.js +1 -1
  42. package/dist/{logger-D0GCSDQq.js → logger-B_71hN6W.js} +1 -1
  43. package/dist/{logging-DV-p52N0.js → logging-DRjvUOIh.js} +1 -1
  44. package/dist/{media-text-BTwzADS_.js → media-text-JudlYOSc.js} +1 -1
  45. package/dist/{messages-DxQJkhxs.js → messages-BW0s-6Y9.js} +7 -7
  46. package/dist/{monitor-VyWlSLwo.js → monitor-Ddfc-vjX.js} +394 -384
  47. package/dist/plugin-entry.handlers.runtime.js +3 -3
  48. package/dist/probe.runtime-Dr91B_X3.js +2 -0
  49. package/dist/profile-D-Wubo0A.js +108 -0
  50. package/dist/{profile-update-CffmyW_4.js → profile-update-BkgWYDIp.js} +3 -2
  51. package/dist/{reaction-events-B00WSi98.js → reaction-events-nfUbFLdV.js} +9 -6
  52. package/dist/{recovery-key-store-BNnHvXdk.js → recovery-key-store-CognuDys.js} +5 -4
  53. package/dist/{resolve-targets-nm2L48sh.js → resolve-targets-BJAPY4Vb.js} +1 -1
  54. package/dist/{resolver.runtime-DS6uPaEe.js → resolver.runtime-LWJELYq5.js} +1 -1
  55. package/dist/{room-info-CAFZ3Z9J.js → room-info-BXQA7y10.js} +12 -3
  56. package/dist/runtime-api.js +6 -3
  57. package/dist/{sdk-bUytQHx7.js → sdk-DjaQFCHc.js} +229 -120
  58. package/dist/{secret-contract-M3hRmGO-.js → secret-contract-CufozuyJ.js} +1 -1
  59. package/dist/secret-contract-api.js +1 -1
  60. package/dist/{send-BldGYG8g.js → send-ZDLU4JTk.js} +1462 -1196
  61. package/dist/session-binding-contract-api.js +1 -1
  62. package/dist/{setup-bootstrap-Deleiibz.js → setup-bootstrap-BaXkhgJg.js} +4 -4
  63. package/dist/{setup-core-BVfBv2ai.js → setup-core-DQn6b5vi.js} +17 -266
  64. package/dist/setup-plugin-api.js +1 -44
  65. package/dist/{setup-surface-BBq3WeqX.js → setup-surface-DlhJdrNI.js} +9 -11
  66. package/dist/{startup-verification-wm3_i88s.js → startup-verification-Cs08ca8u.js} +3 -3
  67. package/dist/{storage-BvAkgzvT.js → storage-BsGuHngK.js} +3 -3
  68. package/dist/{thread-bindings-DGbl3vDW.js → thread-bindings-CcHZP3w2.js} +7 -4
  69. package/dist/{tool-actions.runtime-uu9blSqO.js → tool-actions.runtime-DmdRL0bN.js} +35 -18
  70. package/dist/{verification-DYMQ1QpI.js → verification-C7ig-bQE.js} +2 -2
  71. package/openclaw.plugin.json +54 -1
  72. package/package.json +4 -4
  73. package/dist/active-client-DXvz2gCo.js +0 -20
  74. package/dist/client-Dbso3-0V.js +0 -30
  75. package/dist/create-client-BmSU-q-D.js +0 -61
  76. package/dist/credentials-read-DVmFCm7X.js +0 -77
  77. package/dist/exec-approval-resolver-BCgqRtZS.js +0 -16
  78. package/dist/preflight-audio.runtime-BZxxQsxY.js +0 -11
  79. package/dist/probe.runtime-BuieqmS3.js +0 -3
  80. package/dist/record-shared-CWWx6fvI.js +0 -2
  81. package/dist/shared-CUMWxcMz.js +0 -673
  82. package/dist/sync-state-CWbp0QSY.js +0 -12
  83. package/dist/{runtime-api-D1xI_cvh.js → runtime-api-BGO16Fu8.js} +3 -3
@@ -1,51 +1,50 @@
1
1
  import { a as resolveMatrixAccountConfig, i as resolveMatrixAccountAllowlistConfig } from "./account-config-BZWN9tGS.js";
2
2
  import { t as getMatrixRuntime } from "./runtime-6S3DNFNv.js";
3
- import { n as resolveConfiguredMatrixBotUserIds } from "./accounts-DfngqebB.js";
4
- import { a as buildAllowlistResolutionSummary, c as createTypingCallbacks, d as logInboundDrop, f as logTypingFailure, h as toLocationContext, i as addAllowlistUserEntriesFromConfigEntry, l as formatLocationText, m as summarizeMapping, n as resolveMatrixStoredSessionMeta, o as canonicalizeAllowlistWithResolvedIds, p as patchAllowlistUsersInConfigEntries, r as resolveMatrixRoomConfig, s as createReplyPrefixOptions, u as getAgentScopedMediaLocalRoots } from "./channel-vj788dNZ.js";
5
- import { a as normalizeMatrixUserId, i as normalizeMatrixAllowList, o as resolveMatrixAllowListMatch } from "./config-schema-Djxw3C6b.js";
3
+ import { n as resolveConfiguredMatrixBotUserIds } from "./accounts-BCzyubQt.js";
4
+ import { a as buildAllowlistResolutionSummary, c as createTypingCallbacks, d as logInboundDrop, f as logTypingFailure, h as toLocationContext, i as addAllowlistUserEntriesFromConfigEntry, l as formatLocationText, m as summarizeMapping, n as resolveMatrixStoredSessionMeta, o as canonicalizeAllowlistWithResolvedIds, p as patchAllowlistUsersInConfigEntries, r as resolveMatrixRoomConfig, s as createReplyPrefixOptions, u as getAgentScopedMediaLocalRoots } from "./channel-VSrHgTON.js";
5
+ import { a as normalizeMatrixUserId, i as normalizeMatrixAllowList, o as resolveMatrixAllowListMatch } from "./channel.setup-PpxRP9Du.js";
6
6
  import { t as isMatrixQualifiedUserId } from "./target-ids-B-5aQxwn.js";
7
- import { t as formatMatrixErrorMessage } from "./errors-C47hvAF8.js";
8
- import { D as parsePollStartContent, S as formatPollAsText, T as isPollStartType, g as MATRIX_OPENCLAW_FINALIZED_PREVIEW_KEY, h as readJoinedMatrixMembers, m as isStrictDirectMembership, p as hasDirectMatrixMemberFlag, r as sendMessageMatrix, u as promoteMatrixDirectRoomCandidate, v as chunkMatrixText, w as isPollEventType } from "./send-BldGYG8g.js";
9
- import { t as createMatrixThreadBindingManager } from "./thread-bindings-DGbl3vDW.js";
10
- import { i as createMatrixInboundEventDeduper } from "./inbound-dedupe-CaBLblef.js";
11
- import { a as resolveMatrixMessageAttachment, c as fetchMatrixPollSnapshot, i as isLikelyBareFilename, n as formatMatrixMediaUnavailableText, o as resolveMatrixMessageBody, r as formatMatrixMessageText, t as formatMatrixMediaTooLargeText } from "./media-text-BTwzADS_.js";
12
- import { n as setActiveMatrixClient } from "./active-client-DXvz2gCo.js";
7
+ import { C as promoteMatrixDirectRoomCandidate, T as MATRIX_OPENCLAW_FINALIZED_PREVIEW_KEY, _ as parsePollStartContent, c as chunkMatrixText, f as formatPollAsText, h as isPollStartType, m as isPollEventType, r as sendMessageMatrix } from "./send-ZDLU4JTk.js";
8
+ import { i as isStrictDirectMembership, n as hasDirectMatrixMemberFlag, o as readJoinedMatrixMembers } from "./direct-room-RinHjtqX.js";
9
+ import { t as createMatrixThreadBindingManager } from "./thread-bindings-CcHZP3w2.js";
10
+ import { a as resolveMatrixMessageAttachment, c as fetchMatrixPollSnapshot, i as isLikelyBareFilename, n as formatMatrixMediaUnavailableText, o as resolveMatrixMessageBody, r as formatMatrixMessageText, t as formatMatrixMediaTooLargeText } from "./media-text-JudlYOSc.js";
13
11
  import { t as isBunRuntime } from "./runtime-BefyhPWv.js";
14
- import { d as backfillMatrixAuthDeviceIdAfterStartup, f as resolveMatrixAuth, i as resolveSharedMatrixClient, l as isMatrixStartupAbortError, n as releaseSharedClientInstance, p as resolveMatrixAuthContext, u as throwIfMatrixStartupAborted } from "./shared-CUMWxcMz.js";
15
- import "./client-Dbso3-0V.js";
12
+ import { a as throwIfMatrixStartupAborted, c as resolveMatrixAuth, i as isMatrixStartupAbortError, l as resolveMatrixAuthContext, n as acquireSharedMatrixClient, s as backfillMatrixAuthDeviceIdAfterStartup } from "./client-CeGw0G5S.js";
16
13
  import { i as isMatrixMediaSizeLimitError, r as MatrixMediaSizeLimitError } from "./http-client-CycYxU9-.js";
17
- import { d as resolveAllowlistProviderRuntimeGroupPolicy, f as resolveDefaultGroupPolicy, g as warnMissingProviderGroupPolicyFallbackOnce, h as resolveThreadBindingMaxAgeMsForChannel, m as resolveThreadBindingIdleTimeoutMsForChannel, t as GROUP_POLICY_BLOCKED_LABEL } from "./runtime-api-D1xI_cvh.js";
18
- import { t as resolveMatrixTargets } from "./resolve-targets-nm2L48sh.js";
19
- import { t as formatMatrixEncryptedEventDisabledWarning } from "./encryption-guidance-CbEFe38F.js";
20
- import { n as isMatrixReadySyncState, r as isMatrixTerminalSyncState, t as isMatrixDisconnectedSyncState } from "./sync-state-CWbp0QSY.js";
21
- import { n as setBoundedMap, t as createMatrixRoomInfoResolver } from "./room-info-CAFZ3Z9J.js";
14
+ import { d as resolveAllowlistProviderRuntimeGroupPolicy, f as resolveDefaultGroupPolicy, g as warnMissingProviderGroupPolicyFallbackOnce, h as resolveThreadBindingMaxAgeMsForChannel, m as resolveThreadBindingIdleTimeoutMsForChannel, t as GROUP_POLICY_BLOCKED_LABEL } from "./runtime-api-BGO16Fu8.js";
15
+ import { t as resolveMatrixTargets } from "./resolve-targets-BJAPY4Vb.js";
16
+ import { t as formatMatrixEncryptedEventDisabledWarning } from "./encryption-guidance-DmLY8NiO.js";
17
+ import { createMatrixInboundEventDeduper } from "./inbound-dedupe-RvSLqdsz.js";
18
+ import { a as isMatrixAccessTokenInvalidatedError, d as isMatrixDisconnectedSyncState, f as isMatrixReadySyncState, p as isMatrixTerminalSyncState } from "./client-support-DLj4vDeu.js";
19
+ import { n as setBoundedMap, t as createMatrixRoomInfoResolver } from "./room-info-BXQA7y10.js";
22
20
  import { a as EventType, i as resolveMatrixThreadRouting, n as resolveMatrixReplyToEventId, o as RelationType, r as resolveMatrixThreadRootId, t as resolveMatrixInboundRoute } from "./route-DY6at4qJ.js";
23
21
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
24
- import { buildChannelProgressDraftLineForEntry, createChannelProgressDraftGate, createMessageReceiptFromOutboundResults, createPreviewMessageReceipt, defineFinalizableLivePreviewAdapter, deliverWithFinalizableLivePreviewAdapter, formatChannelProgressDraftLine, formatChannelProgressDraftText, isChannelProgressDraftWorkToolName, listMessageReceiptPlatformIds, mergeChannelProgressDraftLine, normalizeChannelProgressDraftLineIdentity, resolveChannelProgressDraftMaxLines, resolveChannelStreamingBlockEnabled, waitUntilAbort } from "openclaw/plugin-sdk/channel-outbound";
22
+ import { buildChannelProgressDraftLineForEntry, createChannelProgressDraftCompositor, createMessageReceiptFromOutboundResults, createPreviewMessageReceipt, defineFinalizableLivePreviewAdapter, deliverWithFinalizableLivePreviewAdapter, formatChannelProgressDraftLine, formatChannelProgressDraftText, listMessageReceiptPlatformIds, resolveChannelStreamingBlockEnabled, waitUntilAbort } from "openclaw/plugin-sdk/channel-outbound";
25
23
  import { normalizeLowercaseStringOrEmpty, normalizeNullableString, normalizeOptionalString, normalizeStringifiedEntries, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
26
24
  import { stripReasoningTagsFromText } from "openclaw/plugin-sdk/text-chunking";
27
25
  import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-adapter-runtime";
26
+ import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
27
+ import { isFutureDateTimestampMs, parseStrictFiniteNumber, resolveExpiresAtMsFromDurationMs, resolveOptionalIntegerOption } from "openclaw/plugin-sdk/number-runtime";
28
28
  import { resolveInboundLastRouteSessionKey } from "openclaw/plugin-sdk/routing";
29
- import { buildChannelInboundEventContext, createChannelInboundEnvelopeBuilder, createChannelPartialDeliveryError, hasFinalInboundReplyDispatch, isChannelPartialDeliveryError, resolveInboundMentionDecision, toInboundMediaFactsWithMetadata } from "openclaw/plugin-sdk/channel-inbound";
29
+ import { createChannelInboundEnvelopeBuilder, createChannelPartialDeliveryError, hasFinalInboundReplyDispatch, isChannelPartialDeliveryError, resolveInboundMentionDecision, toInboundMediaFactsWithMetadata } from "openclaw/plugin-sdk/channel-inbound";
30
30
  import { getSessionEntry, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
31
- import { isFutureDateTimestampMs, parseStrictFiniteNumber, resolveExpiresAtMsFromDurationMs, resolveOptionalIntegerOption } from "openclaw/plugin-sdk/number-runtime";
32
- import { resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
33
31
  import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
34
32
  import { format } from "node:util";
35
- import { logVerbose } from "openclaw/plugin-sdk/runtime-env";
33
+ import { resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime";
36
34
  import { escapeRegExp, sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
37
35
  import { buildTtsSupplementMediaPayload, getReplyPayloadTtsSupplement } from "openclaw/plugin-sdk/reply-payload";
38
36
  import { resolveAckReaction } from "openclaw/plugin-sdk/channel-feedback";
39
37
  import { registerChannelRuntimeContext } from "openclaw/plugin-sdk/channel-runtime-context";
40
38
  import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/dangerous-name-runtime";
41
39
  import { createChannelIngressResolver, defineStableChannelIngressIdentity } from "openclaw/plugin-sdk/channel-ingress-runtime";
40
+ import { resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
42
41
  import { evaluateSupplementalContextVisibility, resolveChannelContextVisibilityMode } from "openclaw/plugin-sdk/context-visibility-runtime";
43
42
  import { getGlobalHookRunner } from "openclaw/plugin-sdk/plugin-runtime";
44
- import { resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime";
43
+ import { createChannelPreflightAudio } from "openclaw/plugin-sdk/media-understanding-runtime";
45
44
  import { mergePairLoopGuardConfig } from "openclaw/plugin-sdk/pair-loop-guard-runtime";
46
45
  import { buildInboundHistoryFromEntries } from "openclaw/plugin-sdk/reply-history";
47
46
  import { decodeHtmlEntities } from "openclaw/plugin-sdk/html-entity-runtime";
48
- import { createConnectedChannelStatusPatch, createTransportActivityStatusPatch } from "openclaw/plugin-sdk/gateway-runtime";
47
+ import { channelBlockedPatch, channelReadyPatch, channelStoppedPatch, createTransportActivityStatusPatch } from "openclaw/plugin-sdk/gateway-runtime";
49
48
  //#region extensions/matrix/src/matrix/monitor/auto-join.ts
50
49
  function registerMatrixAutoJoin(params) {
51
50
  const { client, accountConfig, runtime } = params;
@@ -60,7 +59,7 @@ function registerMatrixAutoJoin(params) {
60
59
  const allowedRoomIds = new Set(rawAllowlist.filter((entry) => entry.startsWith("!")));
61
60
  const allowedAliases = rawAllowlist.filter((entry) => entry.startsWith("#"));
62
61
  const resolvedAliasRoomIds = /* @__PURE__ */ new Map();
63
- if (autoJoin === "off") return;
62
+ if (autoJoin === "off") return () => {};
64
63
  if (autoJoin === "always") logVerbose("matrix: auto-join enabled for all invites");
65
64
  else logVerbose("matrix: auto-join enabled for allowlist invites");
66
65
  const resolveAllowedAliasRoomId = async (alias) => {
@@ -79,13 +78,8 @@ function registerMatrixAutoJoin(params) {
79
78
  }
80
79
  }))).filter((roomId) => Boolean(roomId));
81
80
  };
82
- const runInviteTask = (roomId, task) => {
83
- Promise.resolve().then(task).catch((err) => {
84
- runtime.error?.(`matrix: auto-join invite handler failed for room ${roomId}: ${String(err)}`);
85
- });
86
- };
87
- client.on("room.invite", (roomId, _inviteEvent) => {
88
- runInviteTask(roomId, async () => {
81
+ const onInvite = (roomId, _inviteEvent) => {
82
+ params.runDetachedTask(`auto-join invite handler room=${roomId}`, async () => {
89
83
  if (autoJoin === "allowlist") {
90
84
  const allowedAliasRoomIds = await resolveAllowedAliasRoomIds();
91
85
  if (!(autoJoinAllowlist.has("*") || allowedRoomIds.has(roomId) || allowedAliasRoomIds.some((resolvedRoomId) => resolvedRoomId === roomId))) {
@@ -100,7 +94,11 @@ function registerMatrixAutoJoin(params) {
100
94
  runtime.error?.(`matrix: failed to join room ${roomId}: ${String(err)}`);
101
95
  }
102
96
  });
103
- });
97
+ };
98
+ client.on("room.invite", onInvite);
99
+ return () => {
100
+ client.off("room.invite", onInvite);
101
+ };
104
102
  }
105
103
  //#endregion
106
104
  //#region extensions/matrix/src/matrix/monitor/config.ts
@@ -719,34 +717,38 @@ async function resolveMatrixMonitorAccessState(params) {
719
717
  });
720
718
  const accountId = params.accountId ?? "default";
721
719
  const eventKind = params.eventKind ?? "message";
720
+ const ingress = createChannelIngressResolver({
721
+ channelId: "matrix",
722
+ accountId,
723
+ identity: matrixIngressIdentity,
724
+ readStoreAllowFrom: async () => params.storeAllowFrom
725
+ });
726
+ const resolveMessageIngress = async (contextBinding, conversation) => await ingress.message({
727
+ subject: { stableId: params.senderId },
728
+ conversation: conversation ?? {
729
+ kind: params.isRoom ? "channel" : "direct",
730
+ id: params.conversationId ?? (params.isRoom ? "matrix-room" : "matrix-dm")
731
+ },
732
+ ...contextBinding ? { contextBinding } : {},
733
+ event: {
734
+ kind: eventKind,
735
+ authMode: "inbound",
736
+ mayPair: params.isRoom ? false : eventKind === "message"
737
+ },
738
+ dmPolicy,
739
+ groupPolicy: params.isRoom ? groupIngress.groupPolicy : "disabled",
740
+ policy: { groupAllowFromFallbackToAllowFrom: false },
741
+ allowFrom: params.allowFrom,
742
+ ...params.isRoom ? { groupAllowFrom: groupIngress.groupAllowFrom } : {}
743
+ });
722
744
  return {
723
745
  effectiveGroupAllowFrom,
724
746
  effectiveRoomUsers,
725
- messageIngress: await createChannelIngressResolver({
726
- channelId: "matrix",
727
- accountId,
728
- identity: matrixIngressIdentity,
729
- readStoreAllowFrom: async () => params.storeAllowFrom
730
- }).message({
731
- subject: { stableId: params.senderId },
732
- conversation: {
733
- kind: params.isRoom ? "group" : "direct",
734
- id: params.isRoom ? "matrix-room" : "matrix-dm"
735
- },
736
- event: {
737
- kind: eventKind,
738
- authMode: "inbound",
739
- mayPair: params.isRoom ? false : eventKind === "message"
740
- },
741
- dmPolicy,
742
- groupPolicy: params.isRoom ? groupIngress.groupPolicy : "disabled",
743
- policy: { groupAllowFromFallbackToAllowFrom: false },
744
- allowFrom: params.allowFrom,
745
- ...params.isRoom ? { groupAllowFrom: groupIngress.groupAllowFrom } : {}
746
- }),
747
+ messageIngress: await resolveMessageIngress(),
747
748
  accountId,
748
749
  senderId: params.senderId,
749
- isRoom: params.isRoom
750
+ isRoom: params.isRoom,
751
+ resolveMessageIngress
750
752
  };
751
753
  }
752
754
  async function resolveMatrixMonitorCommandAccess(state, params) {
@@ -813,7 +815,7 @@ const matrixVerificationConstants = {
813
815
  const MAX_TRACKED_VERIFICATION_EVENTS = 1024;
814
816
  const SAS_NOTICE_RETRY_DELAY_MS = 750;
815
817
  const VERIFICATION_EVENT_STARTUP_GRACE_MS = 3e4;
816
- const loadMatrixDirectRoomDeps = createLazyRuntimeModule(() => Promise.all([import("./send-BldGYG8g.js").then((n) => n.l), import("./send-BldGYG8g.js").then((n) => n.f)]).then(([directManagementModule, directRoomModule]) => ({
818
+ const loadMatrixDirectRoomDeps = createLazyRuntimeModule(() => Promise.all([import("./send-ZDLU4JTk.js").then((n) => n.S), import("./direct-room-RinHjtqX.js").then((n) => n.t)]).then(([directManagementModule, directRoomModule]) => ({
817
819
  inspectMatrixDirectRooms: directManagementModule.inspectMatrixDirectRooms,
818
820
  isStrictDirectRoom: directRoomModule.isStrictDirectRoom
819
821
  })));
@@ -1253,7 +1255,7 @@ async function resolveMatrixSelfUserId(client, logVerboseMessage) {
1253
1255
  }
1254
1256
  }
1255
1257
  function registerMatrixMonitorEvents(params) {
1256
- const { cfg, client, auth, allowFrom, dmEnabled, dmPolicy, readStoreAllowFrom, directTracker, logVerboseMessage, warnedEncryptedRooms, warnedCryptoMissingRooms, logger, startupGraceMs, getHealthySyncSinceMs, formatNativeDependencyHint, onRoomMessage, runDetachedTask, sasNoticeRetryDelayMs } = params;
1258
+ const { cfg, client, auth, allowFrom, dmEnabled, dmPolicy, readStoreAllowFrom, directTracker, invalidateMemberDisplayName, logVerboseMessage, warnedEncryptedRooms, warnedCryptoMissingRooms, logger, startupGraceMs, getHealthySyncSinceMs, formatNativeDependencyHint, onRoomMessage, runDetachedTask, sasNoticeRetryDelayMs } = params;
1257
1259
  const postHealthySyncDecryptFailureTracker = createMatrixPostHealthySyncDecryptFailureTracker({
1258
1260
  getHealthySyncSinceMs,
1259
1261
  startupGraceMs
@@ -1274,18 +1276,18 @@ function registerMatrixMonitorEvents(params) {
1274
1276
  logVerboseMessage(`matrix: ${label} failed (${String(error)})`);
1275
1277
  });
1276
1278
  };
1277
- client.on("room.message", (roomId, event) => {
1279
+ const onRoomMessageEvent = (roomId, event) => {
1278
1280
  if (routeVerificationEvent(roomId, event)) return;
1279
1281
  runMonitorTask(`room message handler room=${roomId} id=${event.event_id ?? "unknown"}`, async () => {
1280
1282
  await onRoomMessage(roomId, event);
1281
1283
  });
1282
- });
1283
- client.on("room.encrypted_event", (roomId, event) => {
1284
+ };
1285
+ const onEncryptedEvent = (roomId, event) => {
1284
1286
  const eventId = event?.event_id ?? "unknown";
1285
1287
  const eventType = event?.type ?? "unknown";
1286
1288
  logVerboseMessage(`matrix: encrypted event room=${roomId} type=${eventType} id=${eventId}`);
1287
- });
1288
- client.on("room.decrypted_event", (roomId, event) => {
1289
+ };
1290
+ const onDecryptedEvent = (roomId, event) => {
1289
1291
  const eventId = event?.event_id ?? "unknown";
1290
1292
  const eventType = event?.type ?? "unknown";
1291
1293
  logVerboseMessage(`matrix: decrypted event room=${roomId} type=${eventType} id=${eventId}`);
@@ -1294,8 +1296,8 @@ function registerMatrixMonitorEvents(params) {
1294
1296
  runMonitorTask(`decrypted room message handler room=${roomId} id=${event.event_id ?? "unknown"}`, async () => {
1295
1297
  await onRoomMessage(roomId, event);
1296
1298
  });
1297
- });
1298
- client.on("room.failed_decryption", (roomId, event, error) => {
1299
+ };
1300
+ const onFailedDecryption = (roomId, event, error) => {
1299
1301
  runMonitorTask(`failed decryption handler room=${roomId} id=${event.event_id ?? "unknown"}`, async () => {
1300
1302
  const failureState = postHealthySyncDecryptFailureTracker.recordFailure(roomId, event, error);
1301
1303
  const selfUserId = await resolveMatrixSelfUserId(client, logVerboseMessage);
@@ -1329,13 +1331,13 @@ function registerMatrixMonitorEvents(params) {
1329
1331
  });
1330
1332
  logVerboseMessage(`matrix: failed decrypt room=${roomId} id=${event.event_id ?? "unknown"} freshAfterHealthySync=${String(failureState.freshAfterHealthySync)} error=${error.message}`);
1331
1333
  });
1332
- });
1333
- client.on("verification.summary", (summary) => {
1334
+ };
1335
+ const onVerificationSummary = (summary) => {
1334
1336
  runMonitorTask("verification summary handler", async () => {
1335
1337
  await routeVerificationSummary(summary);
1336
1338
  });
1337
- });
1338
- client.on("room.invite", (roomId, event) => {
1339
+ };
1340
+ const onInvite = (roomId, event) => {
1339
1341
  directTracker?.invalidateRoom(roomId);
1340
1342
  const eventId = event?.event_id ?? "unknown";
1341
1343
  const sender = event?.sender ?? "unknown";
@@ -1345,13 +1347,13 @@ function registerMatrixMonitorEvents(params) {
1345
1347
  const rememberedSender = normalizeOptionalString(event?.sender);
1346
1348
  if (rememberedSender && !senderIsInvitee) directTracker?.rememberInvite?.(roomId, rememberedSender);
1347
1349
  logVerboseMessage(`matrix: invite room=${roomId} sender=${sender} direct=${String(isDirect)} id=${eventId}`);
1348
- });
1349
- client.on("room.join", (roomId, event) => {
1350
+ };
1351
+ const onJoin = (roomId, event) => {
1350
1352
  directTracker?.invalidateRoom(roomId);
1351
1353
  const eventId = event?.event_id ?? "unknown";
1352
1354
  logVerboseMessage(`matrix: join room=${roomId} id=${eventId}`);
1353
- });
1354
- client.on("room.event", (roomId, event) => {
1355
+ };
1356
+ const onRoomEvent = (roomId, event) => {
1355
1357
  const eventType = event?.type ?? "unknown";
1356
1358
  if (eventType === EventType.RoomMessageEncrypted) {
1357
1359
  logVerboseMessage(`matrix: encrypted raw event room=${roomId} id=${event?.event_id ?? "unknown"}`);
@@ -1375,6 +1377,7 @@ function registerMatrixMonitorEvents(params) {
1375
1377
  directTracker?.invalidateRoom(roomId);
1376
1378
  const membership = (event?.content)?.membership;
1377
1379
  const stateKey = event.state_key ?? "";
1380
+ if (stateKey) invalidateMemberDisplayName?.(roomId, stateKey);
1378
1381
  logVerboseMessage(`matrix: member event room=${roomId} stateKey=${stateKey} membership=${membership ?? "unknown"}`);
1379
1382
  }
1380
1383
  if (eventType === EventType.Reaction) {
@@ -1384,7 +1387,25 @@ function registerMatrixMonitorEvents(params) {
1384
1387
  return;
1385
1388
  }
1386
1389
  routeVerificationEvent(roomId, event);
1387
- });
1390
+ };
1391
+ client.on("room.message", onRoomMessageEvent);
1392
+ client.on("room.encrypted_event", onEncryptedEvent);
1393
+ client.on("room.decrypted_event", onDecryptedEvent);
1394
+ client.on("room.failed_decryption", onFailedDecryption);
1395
+ client.on("verification.summary", onVerificationSummary);
1396
+ client.on("room.invite", onInvite);
1397
+ client.on("room.join", onJoin);
1398
+ client.on("room.event", onRoomEvent);
1399
+ return () => {
1400
+ client.off("room.message", onRoomMessageEvent);
1401
+ client.off("room.encrypted_event", onEncryptedEvent);
1402
+ client.off("room.decrypted_event", onDecryptedEvent);
1403
+ client.off("room.failed_decryption", onFailedDecryption);
1404
+ client.off("verification.summary", onVerificationSummary);
1405
+ client.off("room.invite", onInvite);
1406
+ client.off("room.join", onJoin);
1407
+ client.off("room.event", onRoomEvent);
1408
+ };
1388
1409
  }
1389
1410
  //#endregion
1390
1411
  //#region extensions/matrix/src/matrix/monitor/ack-config.ts
@@ -1404,42 +1425,21 @@ function resolveMatrixAckReactionConfig(params) {
1404
1425
  }
1405
1426
  //#endregion
1406
1427
  //#region extensions/matrix/src/matrix/monitor/preflight-audio.ts
1407
- const MATRIX_DEFAULT_ECHO_TRANSCRIPT_FORMAT = "📝 \"{transcript}\"";
1408
- const loadMatrixPreflightAudioRuntime = createLazyRuntimeModule(() => import("./preflight-audio.runtime-BZxxQsxY.js"));
1409
1428
  function formatMatrixAudioTranscript(transcript) {
1410
1429
  return `[Audio transcript (machine-generated, untrusted)]: ${JSON.stringify(transcript)}`;
1411
1430
  }
1412
- function formatMatrixAudioTranscriptEcho(transcript, format) {
1413
- return format.replace("{transcript}", () => transcript);
1414
- }
1415
- function suppressMatrixPreflightAudioEcho(cfg) {
1416
- const audio = cfg.tools?.media?.audio;
1417
- if (!audio?.echoTranscript) return cfg;
1418
- return {
1419
- ...cfg,
1420
- tools: {
1421
- ...cfg.tools,
1422
- media: {
1423
- ...cfg.tools?.media,
1424
- audio: {
1425
- ...audio,
1426
- echoTranscript: false
1427
- }
1428
- }
1429
- }
1430
- };
1431
- }
1432
1431
  function isMatrixAudioContent(params) {
1433
1432
  if (params.msgtype === "m.audio") return true;
1434
1433
  if (params.msgtype === "m.file" && typeof params.mimetype === "string") return params.mimetype.toLowerCase().startsWith("audio/");
1435
1434
  return false;
1436
1435
  }
1436
+ const matrixPreflightAudio = createChannelPreflightAudio({
1437
+ channel: "matrix",
1438
+ isAudio: isMatrixAudioContent
1439
+ });
1437
1440
  async function resolveMatrixPreflightAudioTranscript(params) {
1438
- if (params.abortSignal?.aborted) return;
1439
- try {
1440
- const { transcribeFirstAudio } = await loadMatrixPreflightAudioRuntime();
1441
- if (params.abortSignal?.aborted) return;
1442
- const transcript = await transcribeFirstAudio({
1441
+ return await matrixPreflightAudio.resolve({
1442
+ request: {
1443
1443
  ctx: {
1444
1444
  media: [{
1445
1445
  path: params.mediaPath,
@@ -1454,34 +1454,13 @@ async function resolveMatrixPreflightAudioTranscript(params) {
1454
1454
  ChatType: params.chatType,
1455
1455
  SessionKey: params.sessionKey
1456
1456
  },
1457
- cfg: suppressMatrixPreflightAudioEcho(params.cfg)
1458
- });
1459
- return params.abortSignal?.aborted ? void 0 : transcript;
1460
- } catch (err) {
1461
- logVerbose(`matrix: audio preflight transcription failed: ${String(err)}`);
1462
- return;
1463
- }
1457
+ cfg: params.cfg
1458
+ },
1459
+ abortSignal: params.abortSignal
1460
+ });
1464
1461
  }
1465
1462
  async function sendMatrixPreflightAudioTranscriptEcho(params) {
1466
- const audio = params.cfg.tools?.media?.audio;
1467
- if (!audio?.echoTranscript) return;
1468
- const text = formatMatrixAudioTranscriptEcho(params.transcript, audio.echoFormat ?? MATRIX_DEFAULT_ECHO_TRANSCRIPT_FORMAT);
1469
- try {
1470
- const { sendDurableMessageBatch } = await loadMatrixPreflightAudioRuntime();
1471
- const send = await sendDurableMessageBatch({
1472
- cfg: params.cfg,
1473
- channel: "matrix",
1474
- to: params.originatingTo,
1475
- accountId: params.accountId,
1476
- threadId: params.messageThreadId,
1477
- payloads: [{ text }],
1478
- bestEffort: true,
1479
- durability: "best_effort"
1480
- });
1481
- if (send.status === "failed") throw send.error;
1482
- } catch (err) {
1483
- logVerbose(`matrix: audio transcript echo failed: ${String(err)}`);
1484
- }
1463
+ await matrixPreflightAudio.send(params);
1485
1464
  }
1486
1465
  //#endregion
1487
1466
  //#region extensions/matrix/src/matrix/monitor/handler-helpers.ts
@@ -1597,11 +1576,11 @@ async function redactMatrixDraftEvent(client, roomId, draftEventId) {
1597
1576
  function buildMatrixFinalizedPreviewContent() {
1598
1577
  return { [MATRIX_OPENCLAW_FINALIZED_PREVIEW_KEY]: true };
1599
1578
  }
1600
- const loadMatrixSendModule = createLazyRuntimeModule(() => import("./send-BldGYG8g.js").then((n) => n.s));
1579
+ const loadMatrixSendModule = createLazyRuntimeModule(() => import("./send-ZDLU4JTk.js").then((n) => n.s));
1601
1580
  const loadAcpBindingRuntime = createLazyRuntimeModule(() => import("openclaw/plugin-sdk/acp-binding-runtime"));
1602
1581
  const loadSessionBindingRuntime = createLazyRuntimeModule(() => import("openclaw/plugin-sdk/session-binding-runtime"));
1603
- const loadMatrixReactionEvents = createLazyRuntimeModule(() => import("./reaction-events-B00WSi98.js"));
1604
- const loadMatrixDraftStream = createLazyRuntimeModule(() => import("./draft-stream-CtvOXq0Z.js"));
1582
+ const loadMatrixReactionEvents = createLazyRuntimeModule(() => import("./reaction-events-nfUbFLdV.js"));
1583
+ const loadMatrixDraftStream = createLazyRuntimeModule(() => import("./draft-stream-BRi7PRRS.js"));
1605
1584
  async function matrixTextWouldActivateMentions(client, text) {
1606
1585
  const { resolveMatrixMentionsForBody } = await loadMatrixSendModule();
1607
1586
  const mentions = await resolveMatrixMentionsForBody({
@@ -1747,7 +1726,7 @@ function createMatrixThreadContextResolver(params) {
1747
1726
  //#endregion
1748
1727
  //#region extensions/matrix/src/matrix/monitor/handler-context.ts
1749
1728
  async function resolveMatrixInboundContext(config) {
1750
- const { client, core, cfg, accountId, runtime, logVerboseMessage, roomId, event, eventTs, route: _route, isDirectMessage, isRoom, effectiveRoomUsers, groupPolicy, effectiveGroupAllowFrom, contextVisibilityMode, resolveThreadContext, resolveReplyContext, threadRootId, thread, getRoomInfo, senderId, senderName, bodyText, commandBodyText, roomConfig, messageId, inboundHistory, wasMentioned, effectiveWasMentioned, shouldBypassMention, canDetectMention, shouldRequireMention, commandAuthorized, locationPayload, media, preflightAudioTranscript, historyLimit, hasExplicitSessionBinding, dmSessionScope, sharedDmContextNoticeRooms, resolveStorePath: resolveStorePathImpl, createChannelInboundEnvelopeBuilder: createChannelInboundEnvelopeBuilderImpl, finalizeInboundContext } = config;
1729
+ const { client, core, cfg, accountId, resolveMessageIngress, runtime, logVerboseMessage, roomId, event, eventTs, route: _route, isDirectMessage, isRoom, effectiveRoomUsers, groupPolicy, effectiveGroupAllowFrom, contextVisibilityMode, resolveThreadContext, resolveReplyContext, threadRootId, thread, getRoomInfo, senderId, senderName, bodyText, commandBodyText, roomConfig, messageId, inboundHistory, wasMentioned, effectiveWasMentioned, shouldBypassMention, canDetectMention, shouldRequireMention, commandAuthorized, locationPayload, media, preflightAudioTranscript, historyLimit, hasExplicitSessionBinding, dmSessionScope, sharedDmContextNoticeRooms, resolveStorePath: resolveStorePathImpl, createChannelInboundEnvelopeBuilder: createChannelInboundEnvelopeBuilderImpl, finalizeInboundContext } = config;
1751
1730
  const replyToEventId = resolveMatrixReplyToEventId(event.content);
1752
1731
  const threadTarget = thread.threadId;
1753
1732
  const isRoomContextSenderAllowed = (contextSenderId) => {
@@ -1822,7 +1801,18 @@ async function resolveMatrixInboundContext(config) {
1822
1801
  kind: "quote",
1823
1802
  senderAllowed: replySenderAllowed
1824
1803
  }).include);
1825
- const ctxPayload = buildChannelInboundEventContext({
1804
+ const channelIngress = await resolveMessageIngress({
1805
+ agentId: _route.agentId,
1806
+ sessionKey: _route.sessionKey,
1807
+ messageId,
1808
+ inboundEventKind: "user_request"
1809
+ }, {
1810
+ kind: isDirectMessage ? "direct" : "channel",
1811
+ id: roomId,
1812
+ threadId: threadTarget
1813
+ });
1814
+ const ctxPayload = core.channel.inbound.buildContext({
1815
+ channelIngress,
1826
1816
  channel: "matrix",
1827
1817
  contextVisibility: contextVisibilityMode,
1828
1818
  finalize: finalizeInboundContext,
@@ -1891,7 +1881,6 @@ async function resolveMatrixInboundContext(config) {
1891
1881
  extra: {
1892
1882
  GroupSubject: isRoom ? roomName ?? roomId : void 0,
1893
1883
  GroupId: isRoom ? roomId : void 0,
1894
- GroupChannel: isRoom ? roomId : void 0,
1895
1884
  ...locationPayload?.context,
1896
1885
  CommandSource: "text",
1897
1886
  NativeDirectUserId: isDirectMessage ? senderId : void 0
@@ -1937,7 +1926,7 @@ async function resolveMatrixInboundContext(config) {
1937
1926
  //#region extensions/matrix/src/matrix/monitor/handler-draft-controller.ts
1938
1927
  async function createMatrixDraftController(params) {
1939
1928
  const { streaming, previewToolProgressEnabled, replyToMode, messageId, threadTarget, accountConfig, cfg, accountId, roomId, client, logVerboseMessage } = params;
1940
- let draftConsumed = false;
1929
+ let draftDisposition = "active";
1941
1930
  const draftStreamingEnabled = streaming !== "off";
1942
1931
  const quietDraftStreaming = streaming === "quiet" || streaming === "progress";
1943
1932
  const progressDraftStreaming = streaming === "progress";
@@ -1961,77 +1950,40 @@ async function createMatrixDraftController(params) {
1961
1950
  const pendingDraftBoundaries = [];
1962
1951
  const latestQueuedDraftBoundaryOffsets = /* @__PURE__ */ new Map();
1963
1952
  let currentDraftReplyToId = draftReplyToId;
1964
- let previewToolProgressSuppressed = false;
1965
- let previewToolProgressLines = [];
1966
- let latestPlan;
1967
- let latestPlanExplanation;
1953
+ let previewPlan;
1954
+ let previewPlanExplanation;
1955
+ let previewPlanSuppressed = false;
1968
1956
  const progressConfigEntry = accountConfig ?? cfg.channels?.matrix;
1969
1957
  const progressSeed = `${accountId}:${roomId}`;
1970
- const renderProgressDraft = () => {
1971
- if (!draftStream) return;
1972
- const previewText = formatChannelProgressDraftText({
1973
- entry: progressConfigEntry,
1974
- lines: previewToolProgressLines,
1975
- seed: progressSeed,
1976
- formatLine: formatMatrixToolProgressMarkdownCode,
1977
- bullet: "-",
1978
- narration: latestPlanExplanation,
1979
- plan: latestPlan
1980
- });
1981
- if (!previewText) return;
1982
- draftStream.update(previewText);
1983
- };
1984
- const progressDraftGate = createChannelProgressDraftGate({ onStart: renderProgressDraft });
1985
- const pushPreviewToolProgress = async (line, options) => {
1986
- if (!draftStream) return;
1987
- if (options?.toolName !== void 0 && !isChannelProgressDraftWorkToolName(options.toolName)) return;
1988
- const normalized = normalizeChannelProgressDraftLineIdentity(line);
1989
- const progressLine = typeof line === "object" && line !== void 0 ? line : normalized;
1990
- if (!progressDraftStreaming) {
1991
- if (!shouldStreamPreviewToolProgress || previewToolProgressSuppressed || !normalized) return;
1992
- const nextLines = mergeChannelProgressDraftLine(previewToolProgressLines, progressLine, { maxLines: resolveChannelProgressDraftMaxLines(progressConfigEntry) });
1993
- if (nextLines === previewToolProgressLines) return;
1994
- previewToolProgressLines = nextLines;
1995
- draftStream.update(formatChannelProgressDraftText({
1996
- entry: progressConfigEntry,
1997
- lines: previewToolProgressLines,
1998
- seed: progressSeed,
1999
- formatLine: formatMatrixToolProgressMarkdownCode,
2000
- bullet: "-",
2001
- narration: latestPlanExplanation,
2002
- plan: latestPlan
2003
- }));
2004
- return;
2005
- }
2006
- if (shouldStreamPreviewToolProgress && !previewToolProgressSuppressed && normalized) previewToolProgressLines = mergeChannelProgressDraftLine(previewToolProgressLines, progressLine, { maxLines: resolveChannelProgressDraftMaxLines(progressConfigEntry) });
2007
- const alreadyStarted = progressDraftGate.hasStarted;
2008
- const progressActive = await progressDraftGate.noteWork();
2009
- if ((alreadyStarted || progressActive) && progressDraftGate.hasStarted) renderProgressDraft();
2010
- };
2011
- const pushPlanProgress = async (steps, explanation) => {
2012
- latestPlan = steps?.length ? steps.map((entry) => ({ ...entry })) : void 0;
2013
- latestPlanExplanation = explanation?.replace(/\s+/g, " ").trim() || void 0;
2014
- if (!draftStream || previewToolProgressSuppressed) return;
2015
- if (!progressDraftStreaming) {
2016
- renderProgressDraft();
2017
- return;
1958
+ const renderPreviewPlan = () => formatChannelProgressDraftText({
1959
+ entry: progressConfigEntry,
1960
+ lines: [...progressDraft.getSnapshot().lines],
1961
+ seed: progressSeed,
1962
+ formatLine: formatMatrixToolProgressMarkdownCode,
1963
+ bullet: "-",
1964
+ narration: previewPlanExplanation,
1965
+ plan: previewPlan
1966
+ });
1967
+ const progressDraft = createChannelProgressDraftCompositor({
1968
+ entry: progressConfigEntry,
1969
+ mode: streaming === "quiet" ? "partial" : streaming,
1970
+ active: Boolean(draftStream),
1971
+ seed: progressSeed,
1972
+ formatLine: formatMatrixToolProgressMarkdownCode,
1973
+ buildProgressEventLine: (input, options) => input.event === "approval" ? formatChannelProgressDraftLine(input, options) : buildChannelProgressDraftLineForEntry(progressConfigEntry, input, options),
1974
+ update: async (text, options) => {
1975
+ const previewText = !progressDraftStreaming && (previewPlan || previewPlanExplanation) ? renderPreviewPlan() : text.replace(/^• /gmu, "- ");
1976
+ if (!draftStream) return false;
1977
+ draftStream.update(previewText);
1978
+ if (options?.flush) await draftStream.flush();
1979
+ return Boolean(draftStream.eventId());
2018
1980
  }
2019
- const alreadyStarted = progressDraftGate.hasStarted;
2020
- await progressDraftGate.startNow();
2021
- if (alreadyStarted && progressDraftGate.hasStarted) renderProgressDraft();
2022
- };
2023
- const suppressPreviewToolProgressForAnswerText = (text) => {
2024
- if (!text?.trim()) return;
2025
- previewToolProgressSuppressed = true;
2026
- previewToolProgressLines = [];
2027
- latestPlan = void 0;
2028
- latestPlanExplanation = void 0;
2029
- };
1981
+ });
2030
1982
  const resetPreviewToolProgress = () => {
2031
- previewToolProgressSuppressed = false;
2032
- previewToolProgressLines = [];
2033
- latestPlan = void 0;
2034
- latestPlanExplanation = void 0;
1983
+ previewPlan = void 0;
1984
+ previewPlanExplanation = void 0;
1985
+ previewPlanSuppressed = false;
1986
+ progressDraft.reset();
2035
1987
  };
2036
1988
  const buildPreviewToolProgressReplyOptions = () => {
2037
1989
  if (!shouldSuppressDefaultToolProgressMessages) return {};
@@ -2040,73 +1992,29 @@ async function createMatrixDraftController(params) {
2040
1992
  return {
2041
1993
  ...options,
2042
1994
  onToolStart: async (payload) => {
2043
- const toolName = payload.name?.trim();
2044
- await pushPreviewToolProgress(buildChannelProgressDraftLineForEntry(progressConfigEntry, {
2045
- event: "tool",
2046
- itemId: payload.itemId,
2047
- toolCallId: payload.toolCallId,
2048
- name: toolName,
2049
- phase: payload.phase,
2050
- args: payload.args
2051
- }, payload.detailMode ? { detailMode: payload.detailMode } : void 0), { toolName });
1995
+ return await progressDraft.pushToolEvent(payload);
2052
1996
  },
2053
1997
  onItemEvent: async (payload) => {
2054
- await pushPreviewToolProgress(buildChannelProgressDraftLineForEntry(progressConfigEntry, {
2055
- event: "item",
2056
- itemId: payload.itemId,
2057
- toolCallId: payload.toolCallId,
2058
- itemKind: payload.kind,
2059
- title: payload.title,
2060
- name: payload.name,
2061
- phase: payload.phase,
2062
- status: payload.status,
2063
- summary: payload.summary,
2064
- progressText: payload.progressText,
2065
- meta: payload.meta
2066
- }));
1998
+ return await progressDraft.pushItemEvent(payload);
2067
1999
  },
2068
2000
  onPlanUpdate: async (payload) => {
2069
- if (payload.phase !== "update") return;
2070
- await pushPlanProgress(payload.steps, payload.explanation);
2001
+ if (payload.phase !== "update") return false;
2002
+ if (progressDraftStreaming) return await progressDraft.pushPlanProgress(payload.steps, { explanation: payload.explanation });
2003
+ if (!draftStream || previewPlanSuppressed) return false;
2004
+ previewPlan = payload.steps?.length ? payload.steps.map((step) => ({ ...step })) : void 0;
2005
+ previewPlanExplanation = payload.explanation?.replace(/\s+/g, " ").trim() || void 0;
2006
+ const text = renderPreviewPlan();
2007
+ if (text) draftStream.update(text);
2008
+ return false;
2071
2009
  },
2072
2010
  onApprovalEvent: async (payload) => {
2073
- if (payload.phase !== "requested") return;
2074
- await pushPreviewToolProgress(formatChannelProgressDraftLine({
2075
- event: "approval",
2076
- phase: payload.phase,
2077
- title: payload.title,
2078
- command: payload.command,
2079
- reason: payload.reason,
2080
- message: payload.message
2081
- }));
2011
+ return await progressDraft.pushApprovalEvent(payload);
2082
2012
  },
2083
2013
  onCommandOutput: async (payload) => {
2084
- if (payload.phase !== "end") return;
2085
- await pushPreviewToolProgress(buildChannelProgressDraftLineForEntry(progressConfigEntry, {
2086
- event: "command-output",
2087
- itemId: payload.itemId,
2088
- toolCallId: payload.toolCallId,
2089
- phase: payload.phase,
2090
- title: payload.title,
2091
- name: payload.name,
2092
- status: payload.status,
2093
- exitCode: payload.exitCode
2094
- }));
2014
+ return await progressDraft.pushCommandOutputEvent(payload);
2095
2015
  },
2096
2016
  onPatchSummary: async (payload) => {
2097
- if (payload.phase !== "end") return;
2098
- await pushPreviewToolProgress(buildChannelProgressDraftLineForEntry(progressConfigEntry, {
2099
- event: "patch",
2100
- itemId: payload.itemId,
2101
- toolCallId: payload.toolCallId,
2102
- phase: payload.phase,
2103
- title: payload.title,
2104
- name: payload.name,
2105
- added: payload.added,
2106
- modified: payload.modified,
2107
- deleted: payload.deleted,
2108
- summary: payload.summary
2109
- }));
2017
+ return await progressDraft.pushPatchEvent(payload);
2110
2018
  }
2111
2019
  };
2112
2020
  };
@@ -2146,19 +2054,19 @@ async function createMatrixDraftController(params) {
2146
2054
  const resetDraftDeliveryState = async () => {
2147
2055
  await draftStream?.discardPending();
2148
2056
  draftStream?.reset();
2149
- draftConsumed = false;
2057
+ draftDisposition = "active";
2150
2058
  currentDraftMessageGeneration = 0;
2151
2059
  currentDraftBlockOffset = 0;
2152
2060
  latestDraftFullText = "";
2153
2061
  pendingDraftBoundaries.length = 0;
2154
2062
  latestQueuedDraftBoundaryOffsets.clear();
2155
2063
  currentDraftReplyToId = draftReplyToId;
2156
- progressDraftGate.reset();
2064
+ progressDraft.beginNewTurn({ force: true });
2157
2065
  resetPreviewToolProgress();
2158
2066
  };
2159
2067
  return {
2160
2068
  draftStream,
2161
- progressDraftGate,
2069
+ cancelProgressDraft: () => progressDraft.cancel(),
2162
2070
  buildPreviewToolProgressReplyOptions,
2163
2071
  queueDraftBlockBoundary,
2164
2072
  advanceDraftBlockBoundary,
@@ -2166,12 +2074,15 @@ async function createMatrixDraftController(params) {
2166
2074
  resetPreviewToolProgress,
2167
2075
  resetDraftDeliveryState,
2168
2076
  updateDraftFromLatestFullText,
2169
- isDraftConsumed: () => draftConsumed,
2077
+ draftDisposition: () => draftDisposition,
2078
+ beginDraftGeneration: () => {
2079
+ draftDisposition = "active";
2080
+ },
2170
2081
  markDraftConsumed: () => {
2171
- draftConsumed = true;
2082
+ draftDisposition = "consumed";
2172
2083
  },
2173
- clearDraftConsumed: () => {
2174
- draftConsumed = false;
2084
+ markDraftRetained: () => {
2085
+ draftDisposition = "retained";
2175
2086
  },
2176
2087
  currentReplyToId: () => currentDraftReplyToId,
2177
2088
  setCurrentReplyToId: (replyToId) => {
@@ -2181,10 +2092,16 @@ async function createMatrixDraftController(params) {
2181
2092
  currentDraftReplyToId = replyToMode === "all" ? draftReplyToId : void 0;
2182
2093
  },
2183
2094
  onPartialReply: (text) => {
2184
- if (progressDraftStreaming) return;
2095
+ if (progressDraftStreaming) return false;
2185
2096
  latestDraftFullText = text;
2186
- suppressPreviewToolProgressForAnswerText(text);
2097
+ if (text.trim()) {
2098
+ previewPlanSuppressed = true;
2099
+ previewPlan = void 0;
2100
+ previewPlanExplanation = void 0;
2101
+ progressDraft.suppress();
2102
+ }
2187
2103
  updateDraftFromLatestFullText();
2104
+ return false;
2188
2105
  }
2189
2106
  };
2190
2107
  }
@@ -2528,6 +2445,7 @@ async function resolveMatrixIngressAccess(config) {
2528
2445
  roomUsers,
2529
2446
  senderId,
2530
2447
  isRoom,
2448
+ conversationId: roomId,
2531
2449
  accountId,
2532
2450
  eventKind: isReactionEvent ? "reaction" : "message"
2533
2451
  });
@@ -2702,6 +2620,11 @@ function resolveMatrixUserLocalpart(userId) {
2702
2620
  if (colonIndex <= 1) return null;
2703
2621
  return trimmed.slice(1, colonIndex).trim() || null;
2704
2622
  }
2623
+ function hasVisibleNativeMatrixUserMention(text, userId) {
2624
+ const localpart = resolveMatrixUserLocalpart(userId);
2625
+ if (!text || !localpart) return false;
2626
+ return new RegExp(String.raw`(?:^|\p{White_Space})(?:${escapeRegExp(userId)}(?=$|\p{White_Space}|:\p{White_Space}|[,!?;](?=$|\p{White_Space}))|${escapeRegExp(`@${localpart}`)}(?=$|\p{White_Space}|:\p{White_Space}))`, "u").test(text);
2627
+ }
2705
2628
  function resolveMatrixMentionPrefixCandidates(params) {
2706
2629
  const candidates = [];
2707
2630
  const seen = /* @__PURE__ */ new Set();
@@ -2803,7 +2726,7 @@ function resolveMentions(params) {
2803
2726
  displayName: params.displayName,
2804
2727
  mentionRegexes: params.mentionRegexes
2805
2728
  }) : false;
2806
- const metadataBackedUserMention = Boolean(params.userId && mentionedUsers.has(params.userId) && (mentionedInFormattedBody || textMentioned));
2729
+ const metadataBackedUserMention = Boolean(params.userId && mentionedUsers.has(params.userId) && (mentionedInFormattedBody || textMentioned || hasVisibleNativeMatrixUserMention(params.text, params.userId)));
2807
2730
  const metadataBackedRoomMention = Boolean(mentions?.room) && visibleRoomMention;
2808
2731
  const explicitMention = mentionedInFormattedBody || metadataBackedUserMention || metadataBackedRoomMention;
2809
2732
  return {
@@ -2817,6 +2740,7 @@ async function resolveMatrixIngressContent(config) {
2817
2740
  const { handler, params: paramsLocal, access, roomId, event, eventType, isPollEvent, eventTs, senderId, roomHistoryTracker, commitInboundEventIfClaimed } = config;
2818
2741
  const { client, core, cfg, accountId, accountConfig, logger, logVerboseMessage, historyLimit, mediaMaxBytes, dmSessionScope, getMemberDisplayName } = handler;
2819
2742
  const { content: accessContent, messageId, audioPreflightMode, isDirectMessage, isRoom, locationPayload, reservedHistorySlot, threadRootId, thread, historyThreadId, discardReservedHistorySlot, markReservedHistorySlotConsumed, commitInboundEventIfClaimedAndDiscardReserved, roomConfig, allowBotsMode, isConfiguredBotSender, selfUserId, botLoopProtection, roomMatchMeta, getSenderName, accessState, effectiveGroupAllowFrom, effectiveRoomUsers } = access;
2743
+ const { messageIngress, resolveMessageIngress } = accessState;
2820
2744
  let content = accessContent;
2821
2745
  let pollSnapshotPromise = null;
2822
2746
  const getPollSnapshot = async () => {
@@ -2898,7 +2822,7 @@ async function resolveMatrixIngressContent(config) {
2898
2822
  } catch (err) {
2899
2823
  preflightMediaDownloadFailed = true;
2900
2824
  if (isMatrixMediaSizeLimitError(err)) preflightMediaSizeLimitExceeded = true;
2901
- const errorText = formatMatrixErrorMessage(err);
2825
+ const errorText = formatErrorMessage(err);
2902
2826
  logVerboseMessage(`matrix: media download failed room=${roomId} id=${event.event_id ?? "unknown"} type=${content.msgtype} error=${errorText}`);
2903
2827
  logger.warn("matrix media download failed", {
2904
2828
  roomId,
@@ -3046,7 +2970,7 @@ async function resolveMatrixIngressContent(config) {
3046
2970
  } catch (err) {
3047
2971
  mediaDownloadFailed = true;
3048
2972
  if (isMatrixMediaSizeLimitError(err)) mediaSizeLimitExceeded = true;
3049
- const errorText = formatMatrixErrorMessage(err);
2973
+ const errorText = formatErrorMessage(err);
3050
2974
  logVerboseMessage(`matrix: media download failed room=${roomId} id=${event.event_id ?? "unknown"} type=${content.msgtype} error=${errorText}`);
3051
2975
  logger.warn("matrix media download failed", {
3052
2976
  roomId,
@@ -3109,6 +3033,8 @@ async function resolveMatrixIngressContent(config) {
3109
3033
  }, historyThreadId) : void 0;
3110
3034
  if (reservedHistorySlot && preparedTrigger) markReservedHistorySlotConsumed();
3111
3035
  return {
3036
+ messageIngress,
3037
+ resolveMessageIngress,
3112
3038
  route: _route,
3113
3039
  hasExplicitSessionBinding,
3114
3040
  roomConfig,
@@ -3346,12 +3272,12 @@ async function deliverMatrixReplies(params) {
3346
3272
  const { chunks } = chunkMatrixText(rawText, {
3347
3273
  cfg: params.cfg,
3348
3274
  accountId: params.accountId,
3349
- tableMode
3275
+ tableMode,
3276
+ preserveWhitespace: true
3350
3277
  });
3351
3278
  for (const chunk of chunks) {
3352
- const trimmed = chunk.trim();
3353
- if (!trimmed) continue;
3354
- await sendMessageMatrix(params.roomId, trimmed, {
3279
+ if (!chunk.trim()) continue;
3280
+ await sendMessageMatrix(params.roomId, chunk, {
3355
3281
  client: params.client,
3356
3282
  cfg: params.cfg,
3357
3283
  replyToId: replyToIdForReply,
@@ -3392,19 +3318,21 @@ function createMatrixReplyDispatcher(config) {
3392
3318
  const hasRepliedRef = { value: false };
3393
3319
  let finalReplyDeliveryFailed = false;
3394
3320
  let nonFinalReplyDeliveryFailed = false;
3321
+ const beginNextBlockDraft = () => {
3322
+ draftController.beginDraftGeneration();
3323
+ draftController.advanceDraftBlockBoundary({ fallbackToLatestEnd: true });
3324
+ draftStream?.reset();
3325
+ draftController.resetReplyToIdForNextBlock();
3326
+ draftController.updateDraftFromLatestFullText();
3327
+ };
3395
3328
  const { deliver: deliverReply, onError: onReplyError, ...turnDispatcherOptions } = {
3396
3329
  ...prefixOptions,
3397
3330
  humanDelay,
3398
3331
  deliver: async (payload, info) => {
3399
3332
  const completeDelivery = async (result) => {
3400
3333
  if (info.kind === "block") {
3401
- draftController.clearDraftConsumed();
3402
- draftController.advanceDraftBlockBoundary({ fallbackToLatestEnd: true });
3403
- draftStream?.reset();
3404
- draftController.resetReplyToIdForNextBlock();
3405
- draftController.updateDraftFromLatestFullText();
3406
- const { sendTypingMatrix } = await loadMatrixSendModule();
3407
- await sendTypingMatrix(roomId, true, void 0, client).catch(() => {});
3334
+ beginNextBlockDraft();
3335
+ await typingCallbacks.onReplyStart();
3408
3336
  }
3409
3337
  return result;
3410
3338
  };
@@ -3422,9 +3350,25 @@ function createMatrixReplyDispatcher(config) {
3422
3350
  content
3423
3351
  };
3424
3352
  };
3425
- const createSurvivingDraftDelivery = (id, redacted) => {
3426
- const content = redacted ? void 0 : draftStream?.content();
3427
- return content ? createDraftDeliveryResult(id, content) : mergeMatrixReplyDeliveryResults([]);
3353
+ const settleDraftReplacement = async (params) => {
3354
+ const draftDelivery = createDraftDeliveryResult(params.draftEventId, params.draftContent);
3355
+ let replacement;
3356
+ try {
3357
+ replacement = await params.deliver();
3358
+ } catch (error) {
3359
+ draftController.markDraftRetained();
3360
+ throw toMatrixPartialDeliveryError(error, [draftDelivery]);
3361
+ }
3362
+ if (!replacement.visibleReplySent) {
3363
+ draftController.markDraftRetained();
3364
+ return draftDelivery;
3365
+ }
3366
+ if (!await redactMatrixDraftEvent(client, roomId, params.draftEventId)) {
3367
+ draftController.markDraftRetained();
3368
+ return mergeMatrixReplyDeliveryResults([draftDelivery, replacement]);
3369
+ }
3370
+ draftController.markDraftConsumed();
3371
+ return replacement;
3428
3372
  };
3429
3373
  if (draftStream && info.kind !== "tool" && !payload.isCompactionNotice) {
3430
3374
  const hasMedia = Boolean(payload.mediaUrl) || (payload.mediaUrls?.length ?? 0) > 0;
@@ -3433,7 +3377,7 @@ function createMatrixReplyDispatcher(config) {
3433
3377
  ...payload,
3434
3378
  text: ttsSupplement.spokenText
3435
3379
  } : payload;
3436
- if (draftController.isDraftConsumed()) {
3380
+ if (draftController.draftDisposition() !== "active") {
3437
3381
  await draftStream.discardPending();
3438
3382
  return await completeDelivery(await deliverMatrixReplies({
3439
3383
  cfg,
@@ -3511,11 +3455,10 @@ function createMatrixReplyDispatcher(config) {
3511
3455
  }
3512
3456
  }),
3513
3457
  deliverNormally: async () => {
3514
- const draftRedacted = await redactMatrixDraftEvent(client, roomId, draftEventId);
3515
- const survivingDraft = createSurvivingDraftDelivery(draftEventId, draftRedacted);
3516
- let deliveredFallback;
3517
- try {
3518
- deliveredFallback = await deliverMatrixReplies({
3458
+ fallbackResult = await settleDraftReplacement({
3459
+ draftEventId,
3460
+ draftContent: draftStream.content() ?? preparedFinalPreviewContent,
3461
+ deliver: async () => await deliverMatrixReplies({
3519
3462
  cfg,
3520
3463
  replies: [fallbackPayload],
3521
3464
  roomId,
@@ -3529,15 +3472,12 @@ function createMatrixReplyDispatcher(config) {
3529
3472
  accountId,
3530
3473
  mediaLocalRoots,
3531
3474
  tableMode
3532
- });
3533
- } catch (error) {
3534
- throw toMatrixPartialDeliveryError(error, [survivingDraft]);
3535
- }
3536
- fallbackResult = mergeMatrixReplyDeliveryResults([survivingDraft, deliveredFallback]);
3475
+ })
3476
+ });
3537
3477
  return fallbackResult.visibleReplySent;
3538
3478
  }
3539
3479
  });
3540
- draftController.markDraftConsumed();
3480
+ if (previewResult.kind === "preview-finalized") draftController.markDraftConsumed();
3541
3481
  return await completeDelivery(previewResult.kind === "preview-finalized" && previewResult.liveState?.receipt ? createDraftDeliveryResult(draftEventId, finalizedDraftContent ?? preparedFinalPreviewContent) : fallbackResult ?? mergeMatrixReplyDeliveryResults([]));
3542
3482
  } else if (draftEventId && hasMedia && !payloadReplyMismatch) {
3543
3483
  let textEditOk = !mustDeliverFinalNormally;
@@ -3575,44 +3515,15 @@ function createMatrixReplyDispatcher(config) {
3575
3515
  }
3576
3516
  const reusesDraftAsFinalText = Boolean(payloadText?.trim()) && textEditOk;
3577
3517
  const draftContent = draftStream.content();
3578
- const draftRedacted = reusesDraftAsFinalText ? false : await redactMatrixDraftEvent(client, roomId, draftEventId);
3579
3518
  const mediaPayload = ttsSupplement && reusesDraftAsFinalText ? buildTtsSupplementMediaPayload(payload) : {
3580
3519
  ...payload,
3581
3520
  text: reusesDraftAsFinalText ? void 0 : payload.text ?? (ttsSupplement?.visibleTextAlreadyDelivered === true ? void 0 : ttsSupplement?.spokenText)
3582
3521
  };
3583
3522
  const providerDraftContent = finalizedDraftContent ?? preparedPayloadContent;
3584
- const previewDelivery = reusesDraftAsFinalText && providerDraftContent ? createDraftDeliveryResult(draftEventId, providerDraftContent) : !draftRedacted && draftContent ? createDraftDeliveryResult(draftEventId, draftContent) : mergeMatrixReplyDeliveryResults([]);
3585
- let mediaDelivery;
3586
- try {
3587
- mediaDelivery = await deliverMatrixReplies({
3588
- cfg,
3589
- replies: [mediaPayload],
3590
- roomId,
3591
- client,
3592
- runtime,
3593
- textLimit,
3594
- replyToMode,
3595
- hasRepliedRef,
3596
- threadId: threadTarget,
3597
- replyToId: threadTarget ?? replyToEventId ?? void 0,
3598
- accountId,
3599
- mediaLocalRoots,
3600
- tableMode
3601
- });
3602
- } catch (error) {
3603
- throw toMatrixPartialDeliveryError(error, [previewDelivery]);
3604
- }
3605
- draftController.markDraftConsumed();
3606
- return await completeDelivery(mergeMatrixReplyDeliveryResults([previewDelivery, mediaDelivery]));
3607
- }
3608
- const shouldRedactDraft = Boolean(draftEventId) && (payload.isError || payloadReplyMismatch || mustDeliverFinalNormally || draftFinalTextNeedsNormalMentionDelivery);
3609
- const draftRedacted = shouldRedactDraft && draftEventId ? await redactMatrixDraftEvent(client, roomId, draftEventId) : false;
3610
- const survivingDraft = shouldRedactDraft && draftEventId ? createSurvivingDraftDelivery(draftEventId, draftRedacted) : mergeMatrixReplyDeliveryResults([]);
3611
- let deliveredFallback;
3612
- try {
3613
- deliveredFallback = await deliverMatrixReplies({
3523
+ const previewDelivery = reusesDraftAsFinalText && providerDraftContent ? createDraftDeliveryResult(draftEventId, providerDraftContent) : draftContent ? createDraftDeliveryResult(draftEventId, draftContent) : mergeMatrixReplyDeliveryResults([]);
3524
+ const deliverMedia = async () => await deliverMatrixReplies({
3614
3525
  cfg,
3615
- replies: [fallbackPayload],
3526
+ replies: [mediaPayload],
3616
3527
  roomId,
3617
3528
  client,
3618
3529
  runtime,
@@ -3625,11 +3536,46 @@ function createMatrixReplyDispatcher(config) {
3625
3536
  mediaLocalRoots,
3626
3537
  tableMode
3627
3538
  });
3628
- } catch (error) {
3629
- throw toMatrixPartialDeliveryError(error, [survivingDraft]);
3539
+ if (reusesDraftAsFinalText) {
3540
+ draftController.markDraftConsumed();
3541
+ let mediaDelivery;
3542
+ try {
3543
+ mediaDelivery = await deliverMedia();
3544
+ } catch (error) {
3545
+ throw toMatrixPartialDeliveryError(error, [previewDelivery]);
3546
+ }
3547
+ return await completeDelivery(mergeMatrixReplyDeliveryResults([previewDelivery, mediaDelivery]));
3548
+ }
3549
+ if (draftContent) return await completeDelivery(await settleDraftReplacement({
3550
+ draftEventId,
3551
+ draftContent,
3552
+ deliver: deliverMedia
3553
+ }));
3554
+ return await completeDelivery(await deliverMedia());
3630
3555
  }
3631
- if (shouldRedactDraft || deliveredFallback.visibleReplySent) draftController.markDraftConsumed();
3632
- return await completeDelivery(mergeMatrixReplyDeliveryResults([survivingDraft, deliveredFallback]));
3556
+ const shouldRedactDraft = Boolean(draftEventId) && (payload.isError || payloadReplyMismatch || mustDeliverFinalNormally || draftFinalTextNeedsNormalMentionDelivery);
3557
+ const deliverFallback = async () => await deliverMatrixReplies({
3558
+ cfg,
3559
+ replies: [fallbackPayload],
3560
+ roomId,
3561
+ client,
3562
+ runtime,
3563
+ textLimit,
3564
+ replyToMode,
3565
+ hasRepliedRef,
3566
+ threadId: threadTarget,
3567
+ replyToId: threadTarget ?? replyToEventId ?? void 0,
3568
+ accountId,
3569
+ mediaLocalRoots,
3570
+ tableMode
3571
+ });
3572
+ const draftContent = draftStream.content();
3573
+ if (shouldRedactDraft && draftEventId && draftContent) return await completeDelivery(await settleDraftReplacement({
3574
+ draftEventId,
3575
+ draftContent,
3576
+ deliver: deliverFallback
3577
+ }));
3578
+ return await completeDelivery(await deliverFallback());
3633
3579
  }
3634
3580
  return await completeDelivery(await deliverMatrixReplies({
3635
3581
  cfg,
@@ -3650,7 +3596,7 @@ function createMatrixReplyDispatcher(config) {
3650
3596
  onError: (err, info) => {
3651
3597
  if (info.kind === "final") finalReplyDeliveryFailed = true;
3652
3598
  else nonFinalReplyDeliveryFailed = true;
3653
- if (info.kind === "block") draftController.advanceDraftBlockBoundary({ fallbackToLatestEnd: true });
3599
+ if (info.kind === "block") beginNextBlockDraft();
3654
3600
  runtime.error?.(`matrix ${info.kind} reply failed: ${String(err)}`);
3655
3601
  },
3656
3602
  onReplyStart: typingCallbacks.onReplyStart,
@@ -3902,8 +3848,9 @@ function createMatrixRoomMessageHandler(params) {
3902
3848
  })();
3903
3849
  if (!resolvedIngressResult) return;
3904
3850
  if ("deferredPrefix" in resolvedIngressResult) return;
3905
- const { route: _route, hasExplicitSessionBinding, roomConfig, isDirectMessage, isRoom, shouldRequireMention, wasMentioned, effectiveWasMentioned, shouldBypassMention, canDetectMention, commandAuthorized, inboundHistory, senderName, bodyText, commandBodyText, media, preflightAudioTranscript, locationPayload, messageId, triggerSnapshot, threadRootId, thread, botLoopProtection, effectiveGroupAllowFrom, effectiveRoomUsers } = resolvedIngressResult;
3851
+ const { route: _route, hasExplicitSessionBinding, roomConfig, isDirectMessage, isRoom, shouldRequireMention, wasMentioned, effectiveWasMentioned, shouldBypassMention, canDetectMention, commandAuthorized, inboundHistory, senderName, bodyText, commandBodyText, media, preflightAudioTranscript, locationPayload, messageId, triggerSnapshot, threadRootId, thread, botLoopProtection, effectiveGroupAllowFrom, effectiveRoomUsers, resolveMessageIngress } = resolvedIngressResult;
3906
3852
  const inboundContext = await resolveMatrixInboundContext({
3853
+ resolveMessageIngress,
3907
3854
  client,
3908
3855
  core,
3909
3856
  cfg,
@@ -4102,19 +4049,21 @@ function createMatrixRoomMessageHandler(params) {
4102
4049
  },
4103
4050
  dispatcherOptions: {
4104
4051
  ...turnDispatcherOptions,
4105
- onSettled: () => draftController.progressDraftGate.cancel()
4052
+ onSettled: () => draftController.cancelProgressDraft()
4106
4053
  },
4107
4054
  replyOptions: {
4108
4055
  skillFilter: roomConfig?.skills,
4109
4056
  disableBlockStreaming: !blockStreamingEnabled,
4110
4057
  onPartialReply: draftStream ? (payload) => draftController.onPartialReply(payload.text ?? "") : void 0,
4111
4058
  onBlockReplyQueued: draftStream ? (payload, context) => {
4112
- if (payload.isCompactionNotice === true) return;
4059
+ if (payload.isCompactionNotice === true) return false;
4113
4060
  draftController.queueDraftBlockBoundary(payload, context);
4061
+ return false;
4114
4062
  } : void 0,
4115
4063
  onAssistantMessageStart: draftStream ? () => {
4116
4064
  draftController.resetDraftBlockOffsets();
4117
4065
  draftController.resetPreviewToolProgress();
4066
+ return false;
4118
4067
  } : void 0,
4119
4068
  onQueuedFollowupAdmitted: draftStream ? draftController.resetDraftDeliveryState : void 0,
4120
4069
  ...draftController.buildPreviewToolProgressReplyOptions(),
@@ -4151,12 +4100,14 @@ function createMatrixRoomMessageHandler(params) {
4151
4100
  logVerboseMessage(`matrix: delivered ${finalCount} reply${finalCount === 1 ? "" : "ies"} to ${replyTarget}`);
4152
4101
  await commitInboundEventIfClaimed();
4153
4102
  } catch (err) {
4103
+ const draftController = draftControllerRef;
4104
+ if (draftController?.draftStream?.eventId() && draftController.draftDisposition() === "active") draftController.markDraftRetained();
4154
4105
  runtime.error?.(`matrix handler failed: ${String(err)}`);
4155
4106
  } finally {
4156
4107
  const draftStream = draftControllerRef?.draftStream;
4157
4108
  if (draftStream) {
4158
4109
  const draftEventId = await draftStream.stop().catch(() => void 0);
4159
- if (draftEventId && draftControllerRef?.isDraftConsumed() !== true) await redactMatrixDraftEvent(client, roomId, draftEventId);
4110
+ if (draftEventId && draftControllerRef?.draftDisposition() === "active") await redactMatrixDraftEvent(client, roomId, draftEventId);
4160
4111
  }
4161
4112
  inboundReplayClaim?.release();
4162
4113
  }
@@ -4177,10 +4128,10 @@ function shouldPromoteRecentInviteRoom(params) {
4177
4128
  //#endregion
4178
4129
  //#region extensions/matrix/src/matrix/monitor/startup.ts
4179
4130
  const loadMatrixStartupMaintenanceDeps = createLazyRuntimeModule(() => Promise.all([
4180
- import("./setup-core-BVfBv2ai.js").then((n) => n.c),
4131
+ import("./config-update-Bor_Pjsv.js").then((n) => n.t),
4181
4132
  import("./device-health-B4-YXtJR.js").then((n) => n.t),
4182
- import("./setup-core-BVfBv2ai.js").then((n) => n.o),
4183
- import("./startup-verification-wm3_i88s.js")
4133
+ import("./profile-D-Wubo0A.js").then((n) => n.n),
4134
+ import("./startup-verification-Cs08ca8u.js")
4184
4135
  ]).then(([configUpdateModule, deviceHealthModule, profileModule, startupVerificationModule]) => ({
4185
4136
  updateMatrixAccountConfig: configUpdateModule.updateMatrixAccountConfig,
4186
4137
  summarizeMatrixDeviceHealth: deviceHealthModule.summarizeMatrixDeviceHealth,
@@ -4251,7 +4202,7 @@ function cloneLastDisconnect(value) {
4251
4202
  function formatSyncError(error) {
4252
4203
  if (!error) return null;
4253
4204
  if (error instanceof Error) return error.message || error.name || "unknown";
4254
- return formatMatrixErrorMessage(error);
4205
+ return formatErrorMessage(error);
4255
4206
  }
4256
4207
  function createMatrixMonitorStatusController(params) {
4257
4208
  const status = {
@@ -4261,7 +4212,8 @@ function createMatrixMonitorStatusController(params) {
4261
4212
  lastConnectedAt: null,
4262
4213
  lastDisconnect: null,
4263
4214
  lastError: null,
4264
- healthState: "starting"
4215
+ healthState: "starting",
4216
+ lifecycle: "starting"
4265
4217
  };
4266
4218
  const emit = () => {
4267
4219
  params.statusSink?.({
@@ -4270,16 +4222,25 @@ function createMatrixMonitorStatusController(params) {
4270
4222
  });
4271
4223
  };
4272
4224
  const noteConnected = (at = Date.now(), options) => {
4273
- if (status.connected === true) status.lastEventAt = at;
4274
- else Object.assign(status, createConnectedChannelStatusPatch(at));
4225
+ const lastConnectedAt = status.connected === true ? status.lastConnectedAt ?? at : at;
4226
+ Object.assign(status, channelReadyPatch({
4227
+ lastConnectedAt,
4228
+ lastEventAt: at,
4229
+ lastDisconnect: null,
4230
+ healthState: "healthy"
4231
+ }));
4275
4232
  if (options?.transportActivity) Object.assign(status, createTransportActivityStatusPatch(at));
4276
- status.lastError = null;
4277
- status.lastDisconnect = null;
4278
- status.healthState = "healthy";
4279
4233
  emit();
4280
4234
  };
4281
4235
  const noteDisconnected = (paramsLocal) => {
4282
4236
  const at = paramsLocal.at ?? Date.now();
4237
+ const tokenInvalidated = isMatrixAccessTokenInvalidatedError(paramsLocal.error);
4238
+ if (status.lifecycle === "blocked" && status.terminalDisconnect === true && !tokenInvalidated) {
4239
+ status.connected = false;
4240
+ status.lastEventAt = at;
4241
+ emit();
4242
+ return;
4243
+ }
4283
4244
  const error = formatSyncError(paramsLocal.error);
4284
4245
  status.connected = false;
4285
4246
  status.lastEventAt = at;
@@ -4287,8 +4248,13 @@ function createMatrixMonitorStatusController(params) {
4287
4248
  at,
4288
4249
  ...error ? { error } : {}
4289
4250
  };
4290
- status.lastError = error;
4291
4251
  status.healthState = paramsLocal.state.toLowerCase();
4252
+ if (tokenInvalidated) Object.assign(status, channelBlockedPatch(error ?? "Matrix access token invalidated"));
4253
+ else {
4254
+ status.lastError = error;
4255
+ status.lifecycle = "recovering";
4256
+ status.terminalDisconnect = void 0;
4257
+ }
4292
4258
  emit();
4293
4259
  };
4294
4260
  emit();
@@ -4318,9 +4284,14 @@ function createMatrixMonitorStatusController(params) {
4318
4284
  });
4319
4285
  },
4320
4286
  markStopped(at = Date.now()) {
4321
- status.connected = false;
4322
- status.lastEventAt = at;
4323
- if (status.healthState !== "error") status.healthState = "stopped";
4287
+ if (status.lifecycle !== "blocked" && status.healthState !== "error") Object.assign(status, channelStoppedPatch({
4288
+ lastEventAt: at,
4289
+ healthState: "stopped"
4290
+ }));
4291
+ else {
4292
+ status.connected = false;
4293
+ status.lastEventAt = at;
4294
+ }
4324
4295
  emit();
4325
4296
  }
4326
4297
  };
@@ -4385,7 +4356,9 @@ function createMatrixMonitorSyncLifecycle(params) {
4385
4356
  //#region extensions/matrix/src/matrix/monitor/task-runner.ts
4386
4357
  function createMatrixMonitorTaskRunner(params) {
4387
4358
  const inFlight = /* @__PURE__ */ new Set();
4359
+ let closed = false;
4388
4360
  const runDetachedTask = (label, task) => {
4361
+ if (closed) return Promise.resolve();
4389
4362
  const trackedTask = Promise.resolve().then(task).catch((error) => {
4390
4363
  const message = String(error);
4391
4364
  params.logVerboseMessage(`matrix: ${label} failed (${message})`);
@@ -4403,6 +4376,7 @@ function createMatrixMonitorTaskRunner(params) {
4403
4376
  while (inFlight.size > 0) await Promise.allSettled(Array.from(inFlight));
4404
4377
  };
4405
4378
  return {
4379
+ close: () => closed = true,
4406
4380
  runDetachedTask,
4407
4381
  waitForIdle
4408
4382
  };
@@ -4504,28 +4478,30 @@ async function monitorMatrixProvider(opts = {}) {
4504
4478
  statusSink: opts.setStatus
4505
4479
  });
4506
4480
  let cleanedUp = false;
4481
+ let cleanupPromise = null;
4507
4482
  let client = null;
4483
+ let clientLease = null;
4484
+ let monitorLifecycleSignal = opts.abortSignal;
4508
4485
  let threadBindingManager = null;
4509
4486
  const monitorTaskRunner = createMatrixMonitorTaskRunner({
4510
4487
  logger,
4511
4488
  logVerboseMessage
4512
4489
  });
4490
+ let disposeAutoJoin = () => {};
4491
+ let disposeMonitorEvents = () => {};
4513
4492
  let syncLifecycle = null;
4514
- const cleanup = async (mode = "persist") => {
4515
- if (cleanedUp) return;
4493
+ let monitorSetupClosed = false;
4494
+ const cleanup = (mode = "persist") => {
4495
+ if (cleanupPromise) return cleanupPromise;
4516
4496
  cleanedUp = true;
4517
- try {
4518
- client?.stopSyncWithoutPersist();
4519
- if (client && mode === "persist") await client.drainPendingDecryptions("matrix monitor shutdown");
4520
- if (mode === "persist") await monitorTaskRunner.waitForIdle();
4521
- threadBindingManager?.stop();
4522
- if (client) await releaseSharedClientInstance(client, mode);
4523
- } finally {
4524
- client?.off("sync.state", onSyncState);
4525
- syncLifecycle?.dispose();
4526
- statusController.markStopped();
4527
- setActiveMatrixClient(null, auth.accountId);
4528
- }
4497
+ cleanupPromise = (async () => {
4498
+ try {
4499
+ await clientLease?.release({ mode });
4500
+ } finally {
4501
+ statusController.markStopped();
4502
+ }
4503
+ })();
4504
+ return cleanupPromise;
4529
4505
  };
4530
4506
  const defaultGroupPolicy = resolveDefaultGroupPolicy(cfg);
4531
4507
  const { groupPolicy: groupPolicyRaw, providerMissingFallbackApplied } = resolveAllowlistProviderRuntimeGroupPolicy({
@@ -4582,14 +4558,32 @@ async function monitorMatrixProvider(opts = {}) {
4582
4558
  const onSyncState = (state) => {
4583
4559
  noteSyncHealthState(state);
4584
4560
  };
4561
+ const monitorRetirement = {
4562
+ closeTaskAdmission: () => {
4563
+ monitorSetupClosed = true;
4564
+ monitorTaskRunner.close();
4565
+ },
4566
+ detachListeners: () => {
4567
+ disposeAutoJoin();
4568
+ disposeMonitorEvents();
4569
+ client?.off("sync.state", onSyncState);
4570
+ syncLifecycle?.dispose();
4571
+ },
4572
+ waitForTasks: monitorTaskRunner.waitForIdle,
4573
+ cleanup: () => threadBindingManager?.stop()
4574
+ };
4585
4575
  try {
4586
- client = await resolveSharedMatrixClient({
4576
+ clientLease = await acquireSharedMatrixClient({
4587
4577
  cfg,
4588
4578
  auth: authWithLimit,
4589
4579
  startClient: false,
4590
- accountId: auth.accountId
4580
+ accountId: auth.accountId,
4581
+ abortSignal: opts.abortSignal,
4582
+ role: "monitor"
4591
4583
  });
4592
- setActiveMatrixClient(client, auth.accountId);
4584
+ client = clientLease.client;
4585
+ monitorLifecycleSignal = opts.abortSignal ? AbortSignal.any([opts.abortSignal, clientLease.abortSignal]) : clientLease.abortSignal;
4586
+ clientLease.registerMonitorRetirement(monitorRetirement);
4593
4587
  const inboundDeduper = createMatrixInboundEventDeduper({
4594
4588
  auth,
4595
4589
  env: process.env
@@ -4597,11 +4591,11 @@ async function monitorMatrixProvider(opts = {}) {
4597
4591
  syncLifecycle = createMatrixMonitorSyncLifecycle({
4598
4592
  client,
4599
4593
  statusController,
4600
- isStopping: () => cleanedUp || opts.abortSignal?.aborted === true
4594
+ isStopping: () => cleanedUp || monitorLifecycleSignal?.aborted === true
4601
4595
  });
4602
4596
  client.on("sync.state", onSyncState);
4603
4597
  const dropPreStartupMessages = !client.hasPersistedSyncState();
4604
- const { getRoomInfo, getMemberDisplayName } = createMatrixRoomInfoResolver(client);
4598
+ const { getRoomInfo, getMemberDisplayName, invalidateMemberDisplayName } = createMatrixRoomInfoResolver(client);
4605
4599
  const isExplicitlyConfiguredRoom = async (roomId) => {
4606
4600
  const roomInfoForConfig = needsRoomAliasesForConfig ? await getRoomInfo(roomId, { includeAliases: true }) : void 0;
4607
4601
  const aliases = roomInfoForConfig ? [roomInfoForConfig.canonicalAlias ?? "", ...roomInfoForConfig.altAliases].filter(Boolean) : [];
@@ -4639,10 +4633,11 @@ async function monitorMatrixProvider(opts = {}) {
4639
4633
  }
4640
4634
  }
4641
4635
  });
4642
- registerMatrixAutoJoin({
4636
+ disposeAutoJoin = registerMatrixAutoJoin({
4643
4637
  client,
4644
4638
  accountConfig,
4645
- runtime
4639
+ runtime,
4640
+ runDetachedTask: monitorTaskRunner.runDetachedTask
4646
4641
  });
4647
4642
  const handleRoomMessage = createMatrixRoomMessageHandler({
4648
4643
  client,
@@ -4682,7 +4677,7 @@ async function monitorMatrixProvider(opts = {}) {
4682
4677
  getMemberDisplayName,
4683
4678
  needsRoomAliasesForConfig
4684
4679
  });
4685
- threadBindingManager = await createMatrixThreadBindingManager({
4680
+ const createdThreadBindingManager = await createMatrixThreadBindingManager({
4686
4681
  cfg,
4687
4682
  accountId: effectiveAccountId,
4688
4683
  auth,
@@ -4692,8 +4687,14 @@ async function monitorMatrixProvider(opts = {}) {
4692
4687
  maxAgeMs: threadBindingMaxAgeMs,
4693
4688
  logVerboseMessage
4694
4689
  });
4690
+ if (monitorSetupClosed) {
4691
+ createdThreadBindingManager.stop();
4692
+ await cleanup("stop");
4693
+ return;
4694
+ }
4695
+ threadBindingManager = createdThreadBindingManager;
4695
4696
  logVerboseMessage(`matrix: thread bindings ready account=${threadBindingManager.accountId} idleMs=${threadBindingIdleTimeoutMs} maxAgeMs=${threadBindingMaxAgeMs}`);
4696
- registerMatrixMonitorEvents({
4697
+ disposeMonitorEvents = registerMatrixMonitorEvents({
4697
4698
  cfg,
4698
4699
  client,
4699
4700
  auth,
@@ -4706,6 +4707,7 @@ async function monitorMatrixProvider(opts = {}) {
4706
4707
  accountId: effectiveAccountId
4707
4708
  }).catch(() => []),
4708
4709
  directTracker,
4710
+ invalidateMemberDisplayName,
4709
4711
  logVerboseMessage,
4710
4712
  warnedEncryptedRooms,
4711
4713
  warnedCryptoMissingRooms,
@@ -4717,18 +4719,17 @@ async function monitorMatrixProvider(opts = {}) {
4717
4719
  runDetachedTask: monitorTaskRunner.runDetachedTask
4718
4720
  });
4719
4721
  logVerboseMessage("matrix: starting client");
4720
- await resolveSharedMatrixClient({
4721
- cfg,
4722
- auth: authWithLimit,
4723
- accountId: auth.accountId,
4724
- abortSignal: opts.abortSignal
4725
- });
4722
+ await clientLease.start(monitorLifecycleSignal);
4723
+ if (monitorSetupClosed) {
4724
+ await cleanup("stop");
4725
+ return;
4726
+ }
4726
4727
  logVerboseMessage("matrix: client started");
4727
4728
  logger.info(`matrix: logged in as ${auth.userId}`);
4728
4729
  backfillMatrixAuthDeviceIdAfterStartup({
4729
4730
  auth,
4730
4731
  env: process.env,
4731
- abortSignal: opts.abortSignal
4732
+ abortSignal: monitorLifecycleSignal
4732
4733
  }).catch((err) => {
4733
4734
  logVerboseMessage(`matrix: failed to backfill deviceId after startup (${String(err)})`);
4734
4735
  });
@@ -4738,7 +4739,7 @@ async function monitorMatrixProvider(opts = {}) {
4738
4739
  accountId: effectiveAccountId,
4739
4740
  capability: CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY,
4740
4741
  context: { client },
4741
- abortSignal: opts.abortSignal
4742
+ abortSignal: monitorLifecycleSignal
4742
4743
  });
4743
4744
  await runMatrixStartupMaintenance({
4744
4745
  client,
@@ -4757,9 +4758,13 @@ async function monitorMatrixProvider(opts = {}) {
4757
4758
  },
4758
4759
  loadWebMedia: async (url, maxBytes) => await core.media.loadWebMedia(url, maxBytes),
4759
4760
  env: process.env,
4760
- abortSignal: opts.abortSignal
4761
+ abortSignal: monitorLifecycleSignal
4761
4762
  });
4762
- await Promise.race([waitUntilAbort(opts.abortSignal, async () => {
4763
+ if (monitorSetupClosed) {
4764
+ await cleanup("stop");
4765
+ return;
4766
+ }
4767
+ await Promise.race([waitUntilAbort(monitorLifecycleSignal, async () => {
4763
4768
  try {
4764
4769
  logVerboseMessage("matrix: stopping client");
4765
4770
  await cleanup();
@@ -4767,8 +4772,13 @@ async function monitorMatrixProvider(opts = {}) {
4767
4772
  logger.warn("matrix: failed during monitor shutdown cleanup", { error: String(err) });
4768
4773
  }
4769
4774
  }), syncLifecycle.waitForFatalStop()]);
4775
+ await cleanup();
4770
4776
  } catch (err) {
4771
- if (opts.abortSignal?.aborted === true && isMatrixStartupAbortError(err)) {
4777
+ if (monitorSetupClosed) {
4778
+ await cleanup("stop");
4779
+ return;
4780
+ }
4781
+ if (monitorLifecycleSignal?.aborted === true && isMatrixStartupAbortError(err)) {
4772
4782
  await cleanup("stop");
4773
4783
  return;
4774
4784
  }