@gakr-gakr/matrix 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. package/CHANGELOG.md +285 -0
  2. package/SPEC-SUPPORT.md +116 -0
  3. package/api.ts +38 -0
  4. package/auth-presence.ts +56 -0
  5. package/autobot.plugin.json +28 -0
  6. package/channel-plugin-api.ts +3 -0
  7. package/cli-metadata.ts +11 -0
  8. package/contract-api.ts +17 -0
  9. package/doctor-contract-api.ts +1 -0
  10. package/helper-api.ts +3 -0
  11. package/index.ts +55 -0
  12. package/package.json +101 -0
  13. package/plugin-entry.handlers.runtime.ts +1 -0
  14. package/runtime-api.ts +72 -0
  15. package/runtime-heavy-api.ts +1 -0
  16. package/runtime-setter-api.ts +3 -0
  17. package/secret-contract-api.ts +5 -0
  18. package/setup-entry.ts +17 -0
  19. package/setup-plugin-api.ts +3 -0
  20. package/src/account-selection.ts +223 -0
  21. package/src/actions.ts +346 -0
  22. package/src/approval-auth.ts +25 -0
  23. package/src/approval-handler.runtime.ts +595 -0
  24. package/src/approval-ids.ts +6 -0
  25. package/src/approval-native.ts +348 -0
  26. package/src/approval-reaction-auth.ts +45 -0
  27. package/src/approval-reactions.ts +313 -0
  28. package/src/auth-precedence.ts +61 -0
  29. package/src/channel-account-paths.ts +97 -0
  30. package/src/channel.runtime.ts +17 -0
  31. package/src/channel.setup.ts +48 -0
  32. package/src/channel.ts +667 -0
  33. package/src/cli-metadata.ts +19 -0
  34. package/src/cli.ts +2298 -0
  35. package/src/config-adapter.ts +41 -0
  36. package/src/config-schema.ts +159 -0
  37. package/src/config-ui-hints.ts +56 -0
  38. package/src/directory-live.ts +238 -0
  39. package/src/doctor-contract.ts +287 -0
  40. package/src/doctor.ts +262 -0
  41. package/src/env-vars.ts +92 -0
  42. package/src/exec-approval-resolver.ts +23 -0
  43. package/src/exec-approvals.ts +293 -0
  44. package/src/group-mentions.ts +41 -0
  45. package/src/legacy-crypto-inspector-availability.ts +60 -0
  46. package/src/legacy-crypto.ts +531 -0
  47. package/src/legacy-state.ts +156 -0
  48. package/src/matrix/account-config.ts +175 -0
  49. package/src/matrix/accounts.ts +194 -0
  50. package/src/matrix/actions/client.ts +31 -0
  51. package/src/matrix/actions/devices.ts +34 -0
  52. package/src/matrix/actions/limits.ts +6 -0
  53. package/src/matrix/actions/messages.ts +129 -0
  54. package/src/matrix/actions/pins.ts +63 -0
  55. package/src/matrix/actions/polls.ts +109 -0
  56. package/src/matrix/actions/profile.ts +37 -0
  57. package/src/matrix/actions/reactions.ts +59 -0
  58. package/src/matrix/actions/room.ts +71 -0
  59. package/src/matrix/actions/summary.ts +88 -0
  60. package/src/matrix/actions/types.ts +63 -0
  61. package/src/matrix/actions/verification.ts +589 -0
  62. package/src/matrix/actions.ts +37 -0
  63. package/src/matrix/active-client.ts +26 -0
  64. package/src/matrix/async-lock.ts +18 -0
  65. package/src/matrix/backup-health.ts +124 -0
  66. package/src/matrix/client/config-runtime-api.ts +9 -0
  67. package/src/matrix/client/config-secret-input.runtime.ts +1 -0
  68. package/src/matrix/client/config.ts +853 -0
  69. package/src/matrix/client/create-client.ts +105 -0
  70. package/src/matrix/client/env-auth.ts +95 -0
  71. package/src/matrix/client/file-sync-store.ts +289 -0
  72. package/src/matrix/client/logging.ts +140 -0
  73. package/src/matrix/client/migration-snapshot.runtime.ts +1 -0
  74. package/src/matrix/client/private-network-host.ts +1 -0
  75. package/src/matrix/client/runtime.ts +4 -0
  76. package/src/matrix/client/shared.ts +316 -0
  77. package/src/matrix/client/storage.ts +543 -0
  78. package/src/matrix/client/types.ts +50 -0
  79. package/src/matrix/client/url-validation.ts +76 -0
  80. package/src/matrix/client-bootstrap.ts +173 -0
  81. package/src/matrix/client.ts +23 -0
  82. package/src/matrix/config-paths.ts +31 -0
  83. package/src/matrix/config-update.ts +292 -0
  84. package/src/matrix/credentials-read.ts +207 -0
  85. package/src/matrix/credentials-write.runtime.ts +35 -0
  86. package/src/matrix/credentials.ts +95 -0
  87. package/src/matrix/deps.ts +309 -0
  88. package/src/matrix/device-health.ts +31 -0
  89. package/src/matrix/direct-management.ts +349 -0
  90. package/src/matrix/direct-room.ts +128 -0
  91. package/src/matrix/draft-stream.ts +225 -0
  92. package/src/matrix/encryption-guidance.ts +24 -0
  93. package/src/matrix/errors.ts +21 -0
  94. package/src/matrix/format.ts +426 -0
  95. package/src/matrix/legacy-crypto-inspector.ts +95 -0
  96. package/src/matrix/media-errors.ts +20 -0
  97. package/src/matrix/media-text.ts +162 -0
  98. package/src/matrix/monitor/access-state.ts +145 -0
  99. package/src/matrix/monitor/ack-config.ts +27 -0
  100. package/src/matrix/monitor/allowlist.ts +92 -0
  101. package/src/matrix/monitor/auto-join.ts +86 -0
  102. package/src/matrix/monitor/config.ts +569 -0
  103. package/src/matrix/monitor/context-summary.ts +43 -0
  104. package/src/matrix/monitor/direct.ts +296 -0
  105. package/src/matrix/monitor/events.ts +397 -0
  106. package/src/matrix/monitor/handler.ts +2271 -0
  107. package/src/matrix/monitor/inbound-dedupe.ts +267 -0
  108. package/src/matrix/monitor/index.ts +540 -0
  109. package/src/matrix/monitor/legacy-crypto-restore.ts +139 -0
  110. package/src/matrix/monitor/location.ts +108 -0
  111. package/src/matrix/monitor/media.ts +119 -0
  112. package/src/matrix/monitor/mentions.ts +256 -0
  113. package/src/matrix/monitor/reaction-events.ts +197 -0
  114. package/src/matrix/monitor/recent-invite.ts +30 -0
  115. package/src/matrix/monitor/replies.ts +136 -0
  116. package/src/matrix/monitor/reply-context.ts +92 -0
  117. package/src/matrix/monitor/room-history.ts +301 -0
  118. package/src/matrix/monitor/room-info.ts +126 -0
  119. package/src/matrix/monitor/rooms.ts +52 -0
  120. package/src/matrix/monitor/route.ts +179 -0
  121. package/src/matrix/monitor/runtime-api.ts +28 -0
  122. package/src/matrix/monitor/startup-verification.ts +237 -0
  123. package/src/matrix/monitor/startup.ts +218 -0
  124. package/src/matrix/monitor/status.ts +120 -0
  125. package/src/matrix/monitor/sync-lifecycle.ts +91 -0
  126. package/src/matrix/monitor/task-runner.ts +38 -0
  127. package/src/matrix/monitor/test-events.ts +21 -0
  128. package/src/matrix/monitor/thread-context.ts +108 -0
  129. package/src/matrix/monitor/threads.ts +85 -0
  130. package/src/matrix/monitor/types.ts +30 -0
  131. package/src/matrix/monitor/verification-events.ts +643 -0
  132. package/src/matrix/monitor/verification-utils.ts +46 -0
  133. package/src/matrix/outbound-media-runtime.ts +1 -0
  134. package/src/matrix/poll-summary.ts +110 -0
  135. package/src/matrix/poll-types.ts +429 -0
  136. package/src/matrix/probe.runtime.ts +4 -0
  137. package/src/matrix/probe.ts +97 -0
  138. package/src/matrix/profile.ts +184 -0
  139. package/src/matrix/reaction-common.ts +147 -0
  140. package/src/matrix/sdk/crypto-bootstrap.ts +438 -0
  141. package/src/matrix/sdk/crypto-facade.ts +242 -0
  142. package/src/matrix/sdk/crypto-node.runtime.ts +17 -0
  143. package/src/matrix/sdk/crypto-runtime.ts +14 -0
  144. package/src/matrix/sdk/decrypt-bridge.ts +410 -0
  145. package/src/matrix/sdk/event-helpers.ts +83 -0
  146. package/src/matrix/sdk/http-client.ts +87 -0
  147. package/src/matrix/sdk/idb-persistence-lock.ts +51 -0
  148. package/src/matrix/sdk/idb-persistence.ts +286 -0
  149. package/src/matrix/sdk/logger.ts +108 -0
  150. package/src/matrix/sdk/read-response-with-limit.ts +19 -0
  151. package/src/matrix/sdk/recovery-key-store.ts +453 -0
  152. package/src/matrix/sdk/timeout-abort-signal.ts +1 -0
  153. package/src/matrix/sdk/transport-runtime-api.ts +18 -0
  154. package/src/matrix/sdk/transport.ts +352 -0
  155. package/src/matrix/sdk/types.ts +245 -0
  156. package/src/matrix/sdk/verification-manager.ts +795 -0
  157. package/src/matrix/sdk/verification-status.ts +23 -0
  158. package/src/matrix/sdk.ts +2152 -0
  159. package/src/matrix/send/client.ts +93 -0
  160. package/src/matrix/send/formatting.ts +189 -0
  161. package/src/matrix/send/media.ts +244 -0
  162. package/src/matrix/send/targets.ts +104 -0
  163. package/src/matrix/send/types.ts +131 -0
  164. package/src/matrix/send.ts +660 -0
  165. package/src/matrix/session-store-metadata.ts +108 -0
  166. package/src/matrix/startup-abort.ts +44 -0
  167. package/src/matrix/subagent-hooks.ts +308 -0
  168. package/src/matrix/sync-state.ts +27 -0
  169. package/src/matrix/target-ids.ts +79 -0
  170. package/src/matrix/thread-bindings-shared.ts +206 -0
  171. package/src/matrix/thread-bindings.ts +580 -0
  172. package/src/matrix-migration.runtime.ts +9 -0
  173. package/src/migration-config.ts +243 -0
  174. package/src/migration-snapshot-backup.ts +116 -0
  175. package/src/migration-snapshot.ts +53 -0
  176. package/src/onboarding.ts +775 -0
  177. package/src/outbound.ts +248 -0
  178. package/src/plugin-entry.runtime.js +115 -0
  179. package/src/plugin-entry.runtime.ts +70 -0
  180. package/src/profile-update.ts +71 -0
  181. package/src/record-shared.ts +3 -0
  182. package/src/resolve-targets.ts +175 -0
  183. package/src/resolver.runtime.ts +5 -0
  184. package/src/resolver.ts +21 -0
  185. package/src/runtime-api.ts +106 -0
  186. package/src/runtime.ts +13 -0
  187. package/src/secret-contract.ts +174 -0
  188. package/src/session-route.ts +126 -0
  189. package/src/setup-bootstrap.ts +102 -0
  190. package/src/setup-config.ts +222 -0
  191. package/src/setup-contract.ts +90 -0
  192. package/src/setup-core.ts +146 -0
  193. package/src/setup-dm-policy.ts +15 -0
  194. package/src/setup-surface.ts +4 -0
  195. package/src/startup-maintenance.ts +114 -0
  196. package/src/storage-paths.ts +92 -0
  197. package/src/thread-binding-api.ts +23 -0
  198. package/src/tool-actions.runtime.ts +1 -0
  199. package/src/tool-actions.ts +498 -0
  200. package/src/types.ts +257 -0
  201. package/subagent-hooks-api.ts +31 -0
  202. package/test-api.ts +21 -0
  203. package/thread-binding-api.ts +4 -0
  204. package/thread-bindings-runtime.ts +4 -0
  205. package/tsconfig.json +16 -0
@@ -0,0 +1,243 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "autobot/plugin-sdk/account-id";
4
+ import type { AutoBotConfig } from "autobot/plugin-sdk/config-contracts";
5
+ import { resolveStateDir } from "autobot/plugin-sdk/state-paths";
6
+ import { normalizeOptionalString } from "autobot/plugin-sdk/string-coerce-runtime";
7
+ import {
8
+ findMatrixAccountEntry,
9
+ requiresExplicitMatrixDefaultAccount,
10
+ resolveConfiguredMatrixAccountIds,
11
+ resolveMatrixChannelConfig,
12
+ resolveMatrixDefaultOrOnlyAccountId,
13
+ } from "./account-selection.js";
14
+ import { resolveMatrixAccountStringValues } from "./auth-precedence.js";
15
+ import {
16
+ resolveGlobalMatrixEnvConfig,
17
+ resolveScopedMatrixEnvConfig,
18
+ } from "./matrix/client/env-auth.js";
19
+ import { resolveMatrixAccountStorageRoot, resolveMatrixCredentialsPath } from "./storage-paths.js";
20
+
21
+ type MatrixStoredCredentials = {
22
+ homeserver: string;
23
+ userId: string;
24
+ accessToken: string;
25
+ deviceId?: string;
26
+ };
27
+
28
+ type MatrixMigrationAccountTarget = {
29
+ accountId: string;
30
+ homeserver: string;
31
+ userId: string;
32
+ accessToken: string;
33
+ rootDir: string;
34
+ storedDeviceId: string | null;
35
+ };
36
+
37
+ type MatrixLegacyFlatStoreTarget = MatrixMigrationAccountTarget & {
38
+ selectionNote?: string;
39
+ };
40
+
41
+ type MatrixLegacyFlatStoreKind = "state" | "encrypted state";
42
+
43
+ function clean(value: unknown): string {
44
+ return normalizeOptionalString(value) ?? "";
45
+ }
46
+
47
+ function resolveMatrixAccountConfigEntry(
48
+ cfg: AutoBotConfig,
49
+ accountId: string,
50
+ ): Record<string, unknown> | null {
51
+ return findMatrixAccountEntry(cfg, accountId);
52
+ }
53
+
54
+ function resolveMatrixFlatStoreSelectionNote(
55
+ cfg: AutoBotConfig,
56
+ accountId: string,
57
+ ): string | undefined {
58
+ if (resolveConfiguredMatrixAccountIds(cfg).length <= 1) {
59
+ return undefined;
60
+ }
61
+ return (
62
+ `Legacy Matrix flat store uses one shared on-disk state, so it will be migrated into ` +
63
+ `account "${accountId}".`
64
+ );
65
+ }
66
+
67
+ function resolveMatrixMigrationConfigFields(params: {
68
+ cfg: AutoBotConfig;
69
+ env: NodeJS.ProcessEnv;
70
+ accountId: string;
71
+ }): {
72
+ homeserver: string;
73
+ userId: string;
74
+ accessToken: string;
75
+ } {
76
+ const channel = resolveMatrixChannelConfig(params.cfg);
77
+ const account = resolveMatrixAccountConfigEntry(params.cfg, params.accountId);
78
+ const scopedEnv = resolveScopedMatrixEnvConfig(params.accountId, params.env);
79
+ const globalEnv = resolveGlobalMatrixEnvConfig(params.env);
80
+ const normalizedAccountId = normalizeAccountId(params.accountId);
81
+ const resolvedStrings = resolveMatrixAccountStringValues({
82
+ accountId: normalizedAccountId,
83
+ account: {
84
+ homeserver: clean(account?.homeserver),
85
+ userId: clean(account?.userId),
86
+ accessToken: clean(account?.accessToken),
87
+ },
88
+ scopedEnv,
89
+ channel: {
90
+ homeserver: clean(channel?.homeserver),
91
+ userId: clean(channel?.userId),
92
+ accessToken: clean(channel?.accessToken),
93
+ },
94
+ globalEnv,
95
+ });
96
+
97
+ return {
98
+ homeserver: resolvedStrings.homeserver,
99
+ userId: resolvedStrings.userId,
100
+ accessToken: resolvedStrings.accessToken,
101
+ };
102
+ }
103
+
104
+ function loadStoredMatrixCredentials(
105
+ env: NodeJS.ProcessEnv,
106
+ accountId: string,
107
+ ): MatrixStoredCredentials | null {
108
+ const stateDir = resolveStateDir(env, os.homedir);
109
+ const credentialsPath = resolveMatrixCredentialsPath({
110
+ stateDir,
111
+ accountId: normalizeAccountId(accountId),
112
+ });
113
+ try {
114
+ if (!fs.existsSync(credentialsPath)) {
115
+ return null;
116
+ }
117
+ const parsed = JSON.parse(
118
+ fs.readFileSync(credentialsPath, "utf8"),
119
+ ) as Partial<MatrixStoredCredentials>;
120
+ if (
121
+ typeof parsed.homeserver !== "string" ||
122
+ typeof parsed.userId !== "string" ||
123
+ typeof parsed.accessToken !== "string"
124
+ ) {
125
+ return null;
126
+ }
127
+ return {
128
+ homeserver: parsed.homeserver,
129
+ userId: parsed.userId,
130
+ accessToken: parsed.accessToken,
131
+ deviceId: typeof parsed.deviceId === "string" ? parsed.deviceId : undefined,
132
+ };
133
+ } catch {
134
+ return null;
135
+ }
136
+ }
137
+
138
+ function credentialsMatchResolvedIdentity(
139
+ stored: MatrixStoredCredentials | null,
140
+ identity: {
141
+ homeserver: string;
142
+ userId: string;
143
+ accessToken: string;
144
+ },
145
+ ): stored is MatrixStoredCredentials {
146
+ if (!stored || !identity.homeserver) {
147
+ return false;
148
+ }
149
+ if (!identity.userId) {
150
+ if (!identity.accessToken) {
151
+ return false;
152
+ }
153
+ return stored.homeserver === identity.homeserver && stored.accessToken === identity.accessToken;
154
+ }
155
+ return stored.homeserver === identity.homeserver && stored.userId === identity.userId;
156
+ }
157
+
158
+ export function resolveMatrixMigrationAccountTarget(params: {
159
+ cfg: AutoBotConfig;
160
+ env: NodeJS.ProcessEnv;
161
+ accountId: string;
162
+ }): MatrixMigrationAccountTarget | null {
163
+ const stored = loadStoredMatrixCredentials(params.env, params.accountId);
164
+ const resolved = resolveMatrixMigrationConfigFields(params);
165
+ const matchingStored = credentialsMatchResolvedIdentity(stored, {
166
+ homeserver: resolved.homeserver,
167
+ userId: resolved.userId,
168
+ accessToken: resolved.accessToken,
169
+ })
170
+ ? stored
171
+ : null;
172
+ const homeserver = resolved.homeserver;
173
+ const userId = resolved.userId || matchingStored?.userId || "";
174
+ const accessToken = resolved.accessToken || matchingStored?.accessToken || "";
175
+ if (!homeserver || !userId || !accessToken) {
176
+ return null;
177
+ }
178
+
179
+ const stateDir = resolveStateDir(params.env, os.homedir);
180
+ const { rootDir } = resolveMatrixAccountStorageRoot({
181
+ stateDir,
182
+ homeserver,
183
+ userId,
184
+ accessToken,
185
+ accountId: params.accountId,
186
+ });
187
+
188
+ return {
189
+ accountId: params.accountId,
190
+ homeserver,
191
+ userId,
192
+ accessToken,
193
+ rootDir,
194
+ storedDeviceId: matchingStored?.deviceId ?? null,
195
+ };
196
+ }
197
+
198
+ export function resolveLegacyMatrixFlatStoreTarget(params: {
199
+ cfg: AutoBotConfig;
200
+ env: NodeJS.ProcessEnv;
201
+ detectedPath: string;
202
+ detectedKind: MatrixLegacyFlatStoreKind;
203
+ }): MatrixLegacyFlatStoreTarget | { warning: string } {
204
+ const channel = resolveMatrixChannelConfig(params.cfg);
205
+ if (!channel) {
206
+ return {
207
+ warning:
208
+ `Legacy Matrix ${params.detectedKind} detected at ${params.detectedPath}, but channels.matrix is not configured yet. ` +
209
+ 'Configure Matrix, then rerun "autobot doctor --fix" or restart the gateway.',
210
+ };
211
+ }
212
+ if (requiresExplicitMatrixDefaultAccount(params.cfg)) {
213
+ return {
214
+ warning:
215
+ `Legacy Matrix ${params.detectedKind} detected at ${params.detectedPath}, but multiple Matrix accounts are configured and channels.matrix.defaultAccount is not set. ` +
216
+ 'Set "channels.matrix.defaultAccount" to the intended target account before rerunning "autobot doctor --fix" or restarting the gateway.',
217
+ };
218
+ }
219
+
220
+ const accountId = resolveMatrixDefaultOrOnlyAccountId(params.cfg);
221
+ const target = resolveMatrixMigrationAccountTarget({
222
+ cfg: params.cfg,
223
+ env: params.env,
224
+ accountId,
225
+ });
226
+ if (!target) {
227
+ const targetDescription =
228
+ params.detectedKind === "state"
229
+ ? "the new account-scoped target"
230
+ : "the account-scoped target";
231
+ return {
232
+ warning:
233
+ `Legacy Matrix ${params.detectedKind} detected at ${params.detectedPath}, but ${targetDescription} could not be resolved yet ` +
234
+ `(need homeserver, userId, and access token for channels.matrix${accountId === DEFAULT_ACCOUNT_ID ? "" : `.accounts.${accountId}`}). ` +
235
+ 'Start the gateway once with a working Matrix login, or rerun "autobot doctor --fix" after cached credentials are available.',
236
+ };
237
+ }
238
+
239
+ return {
240
+ ...target,
241
+ selectionNote: resolveMatrixFlatStoreSelectionNote(params.cfg, accountId),
242
+ };
243
+ }
@@ -0,0 +1,116 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { writeJsonFileAtomically } from "autobot/plugin-sdk/json-store";
5
+ import { resolveRequiredHomeDir, resolveStateDir } from "autobot/plugin-sdk/state-paths";
6
+
7
+ const MATRIX_MIGRATION_SNAPSHOT_DIRNAME = "autobot-migrations";
8
+
9
+ type MatrixMigrationSnapshotMarker = {
10
+ version: 1;
11
+ createdAt: string;
12
+ archivePath: string;
13
+ trigger: string;
14
+ includeWorkspace: boolean;
15
+ };
16
+
17
+ type MatrixMigrationSnapshotResult = {
18
+ created: boolean;
19
+ archivePath: string;
20
+ markerPath: string;
21
+ };
22
+
23
+ function loadSnapshotMarker(filePath: string): MatrixMigrationSnapshotMarker | null {
24
+ try {
25
+ if (!fs.existsSync(filePath)) {
26
+ return null;
27
+ }
28
+ const parsed = JSON.parse(
29
+ fs.readFileSync(filePath, "utf8"),
30
+ ) as Partial<MatrixMigrationSnapshotMarker>;
31
+ if (
32
+ parsed.version !== 1 ||
33
+ typeof parsed.createdAt !== "string" ||
34
+ typeof parsed.archivePath !== "string" ||
35
+ typeof parsed.trigger !== "string"
36
+ ) {
37
+ return null;
38
+ }
39
+ return {
40
+ version: 1,
41
+ createdAt: parsed.createdAt,
42
+ archivePath: parsed.archivePath,
43
+ trigger: parsed.trigger,
44
+ includeWorkspace: parsed.includeWorkspace === true,
45
+ };
46
+ } catch {
47
+ return null;
48
+ }
49
+ }
50
+
51
+ export function resolveMatrixMigrationSnapshotMarkerPath(
52
+ env: NodeJS.ProcessEnv = process.env,
53
+ ): string {
54
+ const stateDir = resolveStateDir(env, os.homedir);
55
+ return path.join(stateDir, "matrix", "migration-snapshot.json");
56
+ }
57
+
58
+ export function resolveMatrixMigrationSnapshotOutputDir(
59
+ env: NodeJS.ProcessEnv = process.env,
60
+ ): string {
61
+ const homeDir = resolveRequiredHomeDir(env, os.homedir);
62
+ return path.join(homeDir, "Backups", MATRIX_MIGRATION_SNAPSHOT_DIRNAME);
63
+ }
64
+
65
+ export async function maybeCreateMatrixMigrationSnapshot(params: {
66
+ trigger: string;
67
+ env?: NodeJS.ProcessEnv;
68
+ outputDir?: string;
69
+ createBackupArchive?: typeof import("autobot/plugin-sdk/runtime").createBackupArchive;
70
+ log?: { info?: (message: string) => void; warn?: (message: string) => void };
71
+ }): Promise<MatrixMigrationSnapshotResult> {
72
+ const env = params.env ?? process.env;
73
+ const createBackupArchive =
74
+ params.createBackupArchive ?? (await import("autobot/plugin-sdk/runtime")).createBackupArchive;
75
+ const markerPath = resolveMatrixMigrationSnapshotMarkerPath(env);
76
+ const existingMarker = loadSnapshotMarker(markerPath);
77
+ if (existingMarker?.archivePath && fs.existsSync(existingMarker.archivePath)) {
78
+ params.log?.info?.(
79
+ `matrix: reusing existing pre-migration backup snapshot: ${existingMarker.archivePath}`,
80
+ );
81
+ return {
82
+ created: false,
83
+ archivePath: existingMarker.archivePath,
84
+ markerPath,
85
+ };
86
+ }
87
+ if (existingMarker?.archivePath && !fs.existsSync(existingMarker.archivePath)) {
88
+ params.log?.warn?.(
89
+ `matrix: previous migration snapshot is missing (${existingMarker.archivePath}); creating a replacement backup before continuing`,
90
+ );
91
+ }
92
+
93
+ const snapshot = await createBackupArchive({
94
+ output: (() => {
95
+ const outputDir = params.outputDir ?? resolveMatrixMigrationSnapshotOutputDir(env);
96
+ fs.mkdirSync(outputDir, { recursive: true });
97
+ return outputDir;
98
+ })(),
99
+ includeWorkspace: false,
100
+ });
101
+
102
+ const marker: MatrixMigrationSnapshotMarker = {
103
+ version: 1,
104
+ createdAt: snapshot.createdAt,
105
+ archivePath: snapshot.archivePath,
106
+ trigger: params.trigger,
107
+ includeWorkspace: snapshot.includeWorkspace,
108
+ };
109
+ await writeJsonFileAtomically(markerPath, marker);
110
+ params.log?.info?.(`matrix: created pre-migration backup snapshot: ${snapshot.archivePath}`);
111
+ return {
112
+ created: true,
113
+ archivePath: snapshot.archivePath,
114
+ markerPath,
115
+ };
116
+ }
@@ -0,0 +1,53 @@
1
+ import type { AutoBotConfig } from "autobot/plugin-sdk/config-contracts";
2
+ import { detectLegacyMatrixCrypto } from "./legacy-crypto.js";
3
+ import { detectLegacyMatrixState } from "./legacy-state.js";
4
+ import {
5
+ maybeCreateMatrixMigrationSnapshot,
6
+ resolveMatrixMigrationSnapshotMarkerPath,
7
+ resolveMatrixMigrationSnapshotOutputDir,
8
+ } from "./migration-snapshot-backup.js";
9
+
10
+ export type MatrixMigrationStatus = {
11
+ legacyState: ReturnType<typeof detectLegacyMatrixState>;
12
+ legacyCrypto: ReturnType<typeof detectLegacyMatrixCrypto>;
13
+ pending: boolean;
14
+ actionable: boolean;
15
+ };
16
+
17
+ export function resolveMatrixMigrationStatus(params: {
18
+ cfg: AutoBotConfig;
19
+ env?: NodeJS.ProcessEnv;
20
+ }): MatrixMigrationStatus {
21
+ const env = params.env ?? process.env;
22
+ const legacyState = detectLegacyMatrixState({ cfg: params.cfg, env });
23
+ const legacyCrypto = detectLegacyMatrixCrypto({ cfg: params.cfg, env });
24
+ const actionableLegacyState = legacyState !== null && !("warning" in legacyState);
25
+ const actionableLegacyCrypto = legacyCrypto.plans.length > 0 && legacyCrypto.inspectorAvailable;
26
+ return {
27
+ legacyState,
28
+ legacyCrypto,
29
+ pending:
30
+ legacyState !== null || legacyCrypto.plans.length > 0 || legacyCrypto.warnings.length > 0,
31
+ actionable: actionableLegacyState || actionableLegacyCrypto,
32
+ };
33
+ }
34
+
35
+ export function hasPendingMatrixMigration(params: {
36
+ cfg: AutoBotConfig;
37
+ env?: NodeJS.ProcessEnv;
38
+ }): boolean {
39
+ return resolveMatrixMigrationStatus(params).pending;
40
+ }
41
+
42
+ export function hasActionableMatrixMigration(params: {
43
+ cfg: AutoBotConfig;
44
+ env?: NodeJS.ProcessEnv;
45
+ }): boolean {
46
+ return resolveMatrixMigrationStatus(params).actionable;
47
+ }
48
+
49
+ export {
50
+ maybeCreateMatrixMigrationSnapshot,
51
+ resolveMatrixMigrationSnapshotMarkerPath,
52
+ resolveMatrixMigrationSnapshotOutputDir,
53
+ };