spiracha 1.2.0 → 1.3.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 (149) hide show
  1. package/AGENTS.md +50 -12
  2. package/README.md +117 -64
  3. package/apps/ui/AGENTS.md +16 -8
  4. package/apps/ui/README.md +28 -12
  5. package/apps/ui/dist/client/assets/{analytics-Cv0JMDN2.js → analytics-B_hYz65v.js} +1 -1
  6. package/apps/ui/dist/client/assets/antigravity-conversations._conversationId-qiyygB7e.js +1 -0
  7. package/apps/ui/dist/client/assets/antigravity-conversations._conversationId-z1SQC2Kg.js +1 -0
  8. package/apps/ui/dist/client/assets/antigravity-keychain-panel-dYuRWtCf.js +1 -0
  9. package/apps/ui/dist/client/assets/antigravity._workspaceKey-CliqUr7o.js +1 -0
  10. package/apps/ui/dist/client/assets/antigravity._workspaceKey-CnoBzyX6.js +1 -0
  11. package/apps/ui/dist/client/assets/antigravity.index-CakfZz_E.js +1 -0
  12. package/apps/ui/dist/client/assets/antigravity.index-DY7M1KhG.js +1 -0
  13. package/apps/ui/dist/client/assets/badge-aHE9ETVe.js +1 -0
  14. package/apps/ui/dist/client/assets/checkbox-DN3XnJaA.js +1 -0
  15. package/apps/ui/dist/client/assets/cursor-threads._composerId-BMQyx8qG.js +1 -0
  16. package/apps/ui/dist/client/assets/cursor-threads._composerId-BTlaA-tV.js +1 -0
  17. package/apps/ui/dist/client/assets/cursor._workspaceKey-CrgrfevV.js +1 -0
  18. package/apps/ui/dist/client/assets/cursor._workspaceKey-bYS2syGL.js +1 -0
  19. package/apps/ui/dist/client/assets/cursor.index-CTqZMPYU.js +1 -0
  20. package/apps/ui/dist/client/assets/cursor.index-Clsz4E_e.js +2 -0
  21. package/apps/ui/dist/client/assets/{data-table-Bgnh7phF.js → data-table-Cj-v-uyB.js} +2 -2
  22. package/apps/ui/dist/client/assets/delete-confirm-dialog-DTpzBiNK.js +11 -0
  23. package/apps/ui/dist/client/assets/dist-BNAn99Pu.js +1 -0
  24. package/apps/ui/dist/client/assets/download-P3Rp23Ad.js +1 -0
  25. package/apps/ui/dist/client/assets/dropdown-menu-3qB5j9nt.js +1 -0
  26. package/apps/ui/dist/client/assets/es2015-Dwm_turD.js +41 -0
  27. package/apps/ui/dist/client/assets/export-dialog-CazdrASq.js +1 -0
  28. package/apps/ui/dist/client/assets/formatters-BdnWuM1z.js +1 -0
  29. package/apps/ui/dist/client/assets/index-BVFnfS78.js +22 -0
  30. package/apps/ui/dist/client/assets/json-panel-DLkS30sQ.js +1 -0
  31. package/apps/ui/dist/client/assets/metadata-section-jnIkB7dB.js +1 -0
  32. package/apps/ui/dist/client/assets/{metric-card-BJX5rkHK.js → metric-card-CBZuWLzQ.js} +1 -1
  33. package/apps/ui/dist/client/assets/page-header-CnD21cPn.js +1 -0
  34. package/apps/ui/dist/client/assets/projects._project-BLszwvYL.js +1 -0
  35. package/apps/ui/dist/client/assets/projects._project-DvLxYbvk.js +1 -0
  36. package/apps/ui/dist/client/assets/projects.index-COn8woBR.js +1 -0
  37. package/apps/ui/dist/client/assets/projects.index-DYs98skV.js +3 -0
  38. package/apps/ui/dist/client/assets/refresh-ccw-BDrYXjtD.js +1 -0
  39. package/apps/ui/dist/client/assets/reload-error-panel-DLAg0AW2.js +1 -0
  40. package/apps/ui/dist/client/assets/routes-BtF5-coe.js +1 -0
  41. package/apps/ui/dist/client/assets/scroll-text-CqaFm9by.js +1 -0
  42. package/apps/ui/dist/client/assets/select-DbnpwqL6.js +1 -0
  43. package/apps/ui/dist/client/assets/settings-CGX3VleN.js +1 -0
  44. package/apps/ui/dist/client/assets/styles-Ch0r3kMZ.css +1 -0
  45. package/apps/ui/dist/client/assets/text-document-panel-DPleOmmq.js +1 -0
  46. package/apps/ui/dist/client/assets/text-filter-7M6wRo-t.js +2 -0
  47. package/apps/ui/dist/client/assets/threads._threadId-D5w76IB-.js +7 -0
  48. package/apps/ui/dist/client/assets/{threads._threadId-CUiCZSwo.js → threads._threadId-Dx85sI9P.js} +1 -1
  49. package/apps/ui/dist/client/assets/useMutation-MZ3Hr9h9.js +1 -0
  50. package/apps/ui/dist/client/assets/useQuery-Cb4V0AT0.js +1 -0
  51. package/apps/ui/dist/client/icon.svg +28 -0
  52. package/apps/ui/dist/client/manifest.json +6 -16
  53. package/apps/ui/dist/server/assets/_tanstack-start-manifest_v-CBbkUXw6.js +227 -0
  54. package/apps/ui/dist/server/assets/{analytics-2QpLKjlG.js → analytics-CBNOYZwJ.js} +2 -2
  55. package/apps/ui/dist/server/assets/antigravity-conversation-state-HgzS302O.js +16 -0
  56. package/apps/ui/dist/server/assets/antigravity-conversations._conversationId-B9Rm4EXh.js +212 -0
  57. package/apps/ui/dist/server/assets/antigravity-conversations._conversationId-BIdYNy68.js +20 -0
  58. package/apps/ui/dist/server/assets/antigravity-conversations._conversationId-D426O-64.js +11 -0
  59. package/apps/ui/dist/server/assets/antigravity-db-D9gW1D8G.js +576 -0
  60. package/apps/ui/dist/server/assets/antigravity-keychain-DOiuHDwK.js +126 -0
  61. package/apps/ui/dist/server/assets/antigravity-keychain-panel-DcLyBBwd.js +55 -0
  62. package/apps/ui/dist/server/assets/antigravity-queries-CgQhlQ7J.js +37 -0
  63. package/apps/ui/dist/server/assets/antigravity-server-DFUx4Khk.js +114 -0
  64. package/apps/ui/dist/server/assets/antigravity._workspaceKey-3m_MzNFA.js +11 -0
  65. package/apps/ui/dist/server/assets/antigravity._workspaceKey-D42ixtzp.js +210 -0
  66. package/apps/ui/dist/server/assets/antigravity._workspaceKey-DnSlSC-C.js +28 -0
  67. package/apps/ui/dist/server/assets/antigravity.index-DZVT-cac.js +104 -0
  68. package/apps/ui/dist/server/assets/antigravity.index-DudTB3Tq.js +11 -0
  69. package/apps/ui/dist/server/assets/badge-EvdhKK_Z.js +26 -0
  70. package/apps/ui/dist/server/assets/{codex-queries-BH4Cb0v3.js → codex-queries-eOJGfHQj.js} +4 -16
  71. package/apps/ui/dist/server/assets/{codex-server-DqzruLmg.js → codex-server-nrETIF--.js} +149 -140
  72. package/apps/ui/dist/server/assets/createServerRpc-BtXIw2iP.js +12 -0
  73. package/apps/ui/dist/server/assets/createSsrRpc-COf5Zuye.js +16 -0
  74. package/apps/ui/dist/server/assets/cursor-db-B7agkAvM.js +643 -0
  75. package/apps/ui/dist/server/assets/cursor-exporter-types-CI3goo-c.js +34 -0
  76. package/apps/ui/dist/server/assets/cursor-queries-BMhuJeUO.js +65 -0
  77. package/apps/ui/dist/server/assets/cursor-recovery-9bJLs7vG.js +361 -0
  78. package/apps/ui/dist/server/assets/cursor-server-BgylIFgn.js +184 -0
  79. package/apps/ui/dist/server/assets/cursor-threads._composerId-BB0Y_Mao.js +11 -0
  80. package/apps/ui/dist/server/assets/cursor-threads._composerId-BsxFKzoJ.js +218 -0
  81. package/apps/ui/dist/server/assets/cursor-threads._composerId-DXffY_CK.js +18 -0
  82. package/apps/ui/dist/server/assets/cursor-transcript-2iL3KFSK.js +125 -0
  83. package/apps/ui/dist/server/assets/cursor._workspaceKey-BP2J1x_x.js +28 -0
  84. package/apps/ui/dist/server/assets/cursor._workspaceKey-BQd0e-Pd.js +399 -0
  85. package/apps/ui/dist/server/assets/cursor._workspaceKey-nmg3YIOQ.js +11 -0
  86. package/apps/ui/dist/server/assets/cursor.index-CQVxtCm8.js +189 -0
  87. package/apps/ui/dist/server/assets/cursor.index-CcsX7DG0.js +11 -0
  88. package/apps/ui/dist/server/assets/{delete-confirm-dialog-CWqcTXTF.js → delete-confirm-dialog-PCD7S0_M.js} +5 -4
  89. package/apps/ui/dist/server/assets/download-DMmiy1xf.js +92 -0
  90. package/apps/ui/dist/server/assets/{input-B4tEzctc.js → dropdown-menu-Dy_9t6TN.js} +1 -11
  91. package/apps/ui/dist/server/assets/{download-Drctxary.js → export-dialog-DaPlOGFT.js} +1 -92
  92. package/apps/ui/dist/server/assets/json-panel-RYsxWFae.js +16 -0
  93. package/apps/ui/dist/server/assets/{loading-panel-DbLdvjtR.js → loading-panel-BGFnWseS.js} +1 -1
  94. package/apps/ui/dist/server/assets/metadata-section-D6Lbc7D6.js +54 -0
  95. package/apps/ui/dist/server/assets/page-header-VNSaM3xd.js +29 -0
  96. package/apps/ui/dist/server/assets/projects._project-Bshqk7JA.js +12 -0
  97. package/apps/ui/dist/server/assets/{projects._project-gT01HBqH.js → projects._project-DUN3iWfg.js} +4 -4
  98. package/apps/ui/dist/server/assets/{projects._project-DreIU5b0.js → projects._project-Dim9Y0kD.js} +54 -26
  99. package/apps/ui/dist/server/assets/projects.index-BLXOx5eL.js +12 -0
  100. package/apps/ui/dist/server/assets/{projects.index-BYmgSGAj.js → projects.index-DjSQK5dm.js} +23 -27
  101. package/apps/ui/dist/server/assets/{projects.index-CaplpeMy.js → reload-error-panel-BJMxY3U1.js} +5 -6
  102. package/apps/ui/dist/server/assets/{router-Qj5Kn7bl.js → router-DrDgc-LD.js} +131 -44
  103. package/apps/ui/dist/server/assets/{routes-_LbCIjtJ.js → routes-B-GlEe2C.js} +54 -39
  104. package/apps/ui/dist/server/assets/{routes-BtcXuK0x.js → routes-CNHAUMwo.js} +2 -2
  105. package/apps/ui/dist/server/assets/{settings-MvWDgc1u.js → settings-OayxIYQQ.js} +1 -1
  106. package/apps/ui/dist/server/assets/shared-CPRNYIql.js +134 -0
  107. package/apps/ui/dist/server/assets/text-document-panel-D8JbQWAn.js +23 -0
  108. package/apps/ui/dist/server/assets/text-filter-CGKxMCKt.js +36 -0
  109. package/apps/ui/dist/server/assets/{threads._threadId-DcbAJkwf.js → threads._threadId-CJzm4KrZ.js} +3 -3
  110. package/apps/ui/dist/server/assets/{threads._threadId-D5m6ypGw.js → threads._threadId-DODTYddm.js} +69 -76
  111. package/apps/ui/dist/server/server.js +77 -13
  112. package/package.json +21 -11
  113. package/src/export-cursor.ts +244 -0
  114. package/src/lib/antigravity-db.ts +936 -0
  115. package/src/lib/antigravity-exporter-types.ts +70 -0
  116. package/src/lib/antigravity-keychain.ts +203 -0
  117. package/src/lib/codex-browser-db.ts +7 -1
  118. package/src/lib/codex-browser-types.ts +22 -1
  119. package/src/lib/codex-thread-recovery.ts +202 -0
  120. package/src/lib/cursor-db.ts +1096 -0
  121. package/src/lib/cursor-exporter-types.ts +190 -0
  122. package/src/lib/cursor-exporter.ts +266 -0
  123. package/src/lib/cursor-recovery.ts +543 -0
  124. package/src/lib/cursor-transcript.ts +183 -0
  125. package/src/spiracha.ts +16 -3
  126. package/src/ui-cli.ts +2 -2
  127. package/apps/ui/dist/client/assets/checkbox-DjHij7DJ.js +0 -1
  128. package/apps/ui/dist/client/assets/delete-confirm-dialog-CIZy_LXD.js +0 -11
  129. package/apps/ui/dist/client/assets/download-DQtfva4z.js +0 -1
  130. package/apps/ui/dist/client/assets/es2015-DsDKdYCE.js +0 -41
  131. package/apps/ui/dist/client/assets/formatters-CWFrMKSn.js +0 -1
  132. package/apps/ui/dist/client/assets/index-C_-e0lDI.js +0 -22
  133. package/apps/ui/dist/client/assets/input-BbgApiqZ.js +0 -1
  134. package/apps/ui/dist/client/assets/page-header-ODLuGLAB.js +0 -1
  135. package/apps/ui/dist/client/assets/projects._project-C2Pys_bB.js +0 -1
  136. package/apps/ui/dist/client/assets/projects._project-CHvAKvlu.js +0 -1
  137. package/apps/ui/dist/client/assets/projects.index-BmwtS1x-.js +0 -1
  138. package/apps/ui/dist/client/assets/projects.index-CuLw73mt.js +0 -1
  139. package/apps/ui/dist/client/assets/routes-CfnaTOlj.js +0 -1
  140. package/apps/ui/dist/client/assets/select-B1kH_5lx.js +0 -1
  141. package/apps/ui/dist/client/assets/settings-mYTB3sso.js +0 -1
  142. package/apps/ui/dist/client/assets/styles-CMrP9Jb4.css +0 -1
  143. package/apps/ui/dist/client/assets/threads._threadId-C_47okme.js +0 -7
  144. package/apps/ui/dist/client/favicon.ico +0 -0
  145. package/apps/ui/dist/client/logo192.png +0 -0
  146. package/apps/ui/dist/client/logo512.png +0 -0
  147. package/apps/ui/dist/server/assets/_tanstack-start-manifest_v-kj_QB_26.js +0 -99
  148. package/apps/ui/dist/server/assets/page-header-CxdZM86z.js +0 -25
  149. package/apps/ui/dist/server/assets/projects._project-CLSohrBp.js +0 -26
@@ -0,0 +1,576 @@
1
+ import { decryptAntigravitySafeStoragePayload } from "./antigravity-keychain-DOiuHDwK.js";
2
+ import { readdir, stat } from "node:fs/promises";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ //#region ../../src/lib/antigravity-exporter-types.ts
6
+ var DEFAULT_ANTIGRAVITY_IDE_DIR = path.join(os.homedir(), ".gemini", "antigravity-ide");
7
+ var DEFAULT_ANTIGRAVITY_DIR = path.join(os.homedir(), ".gemini", "antigravity");
8
+ var resolveAntigravityRoots = () => {
9
+ const configured = process.env.SPIRACHA_ANTIGRAVITY_DIRS?.trim() || process.env.SPIRACHA_ANTIGRAVITY_DIR?.trim();
10
+ if (configured) return configured.split(path.delimiter).map((entry) => entry.trim()).filter(Boolean);
11
+ return [DEFAULT_ANTIGRAVITY_IDE_DIR, DEFAULT_ANTIGRAVITY_DIR];
12
+ };
13
+ var getAntigravityConversationDir = (root) => path.join(root, "conversations");
14
+ var getAntigravityBrainDir = (root) => path.join(root, "brain");
15
+ var getAntigravitySummaryIndexPath = (root) => path.join(root, "agyhub_summaries_proto.pb");
16
+ //#endregion
17
+ //#region ../../src/lib/antigravity-db.ts
18
+ var UNKNOWN_WORKSPACE = {
19
+ workspaceFolder: null,
20
+ workspaceKey: "unknown",
21
+ workspaceLabel: "Unknown project",
22
+ workspaceUri: null
23
+ };
24
+ var decoder = new TextDecoder();
25
+ var pathExists = async (target) => {
26
+ try {
27
+ await stat(target);
28
+ return true;
29
+ } catch {
30
+ return false;
31
+ }
32
+ };
33
+ var isFileMissingError = (error) => {
34
+ const code = error.code;
35
+ return code === "ENOENT" || code === "ENOTDIR";
36
+ };
37
+ var readVarint = (buffer, start, end) => {
38
+ let value = 0;
39
+ let multiplier = 1;
40
+ for (let index = start; index < end; index += 1) {
41
+ const byte = buffer[index];
42
+ value += (byte & 127) * multiplier;
43
+ if ((byte & 128) === 0) return {
44
+ next: index + 1,
45
+ value
46
+ };
47
+ multiplier *= 128;
48
+ }
49
+ throw new Error("Unterminated protobuf varint");
50
+ };
51
+ var parseProtoFields = (buffer, start = 0, end = buffer.length) => {
52
+ const fields = [];
53
+ let index = start;
54
+ while (index < end) {
55
+ const key = readVarint(buffer, index, end);
56
+ index = key.next;
57
+ const fieldNumber = key.value >> 3;
58
+ const wireType = key.value & 7;
59
+ if (fieldNumber <= 0) throw new Error(`Invalid protobuf field number: ${fieldNumber}`);
60
+ if (wireType === 0) {
61
+ const fieldValue = readVarint(buffer, index, end);
62
+ index = fieldValue.next;
63
+ fields.push({
64
+ fieldNumber,
65
+ value: fieldValue.value,
66
+ wireType
67
+ });
68
+ continue;
69
+ }
70
+ if (wireType === 1) {
71
+ index += 8;
72
+ fields.push({
73
+ fieldNumber,
74
+ wireType
75
+ });
76
+ continue;
77
+ }
78
+ if (wireType === 2) {
79
+ const length = readVarint(buffer, index, end);
80
+ index = length.next;
81
+ const next = index + length.value;
82
+ if (next > end) throw new Error("Invalid protobuf length-delimited field");
83
+ fields.push({
84
+ bytes: buffer.slice(index, next),
85
+ fieldNumber,
86
+ wireType
87
+ });
88
+ index = next;
89
+ continue;
90
+ }
91
+ if (wireType === 5) {
92
+ index += 4;
93
+ fields.push({
94
+ fieldNumber,
95
+ wireType
96
+ });
97
+ continue;
98
+ }
99
+ throw new Error(`Unsupported protobuf wire type: ${wireType}`);
100
+ }
101
+ return fields;
102
+ };
103
+ var firstField = (fields, fieldNumber) => fields.find((field) => field.fieldNumber === fieldNumber) ?? null;
104
+ var fieldString = (fields, fieldNumber) => {
105
+ const field = firstField(fields, fieldNumber);
106
+ if (!field?.bytes) return null;
107
+ return decoder.decode(field.bytes);
108
+ };
109
+ var fieldNumberValue = (fields, fieldNumber) => {
110
+ return firstField(fields, fieldNumber)?.value ?? null;
111
+ };
112
+ var nestedFields = (field) => {
113
+ if (!field?.bytes) return [];
114
+ return parseProtoFields(field.bytes);
115
+ };
116
+ var parseTimestampMs = (field) => {
117
+ const fields = nestedFields(field);
118
+ const seconds = fieldNumberValue(fields, 1);
119
+ if (seconds === null) return null;
120
+ const nanos = fieldNumberValue(fields, 2) ?? 0;
121
+ return seconds * 1e3 + Math.floor(nanos / 1e6);
122
+ };
123
+ var cleanTitle = (value, fallback) => {
124
+ const title = value?.replace(/\s+/g, " ").trim();
125
+ if (!title) return fallback;
126
+ return title.length > 180 ? `${title.slice(0, 177)}...` : title;
127
+ };
128
+ var decodeFileUri = (value) => {
129
+ if (!value.startsWith("file://")) return value;
130
+ try {
131
+ return decodeURIComponent(new URL(value).pathname);
132
+ } catch {
133
+ return decodeURIComponent(value.slice(7));
134
+ }
135
+ };
136
+ var normalizeWorkspaceFolder = (value) => {
137
+ const decoded = decodeFileUri(value.trim());
138
+ return decoded.replace(/\/+$/u, "") || decoded;
139
+ };
140
+ var workspaceFromFolder = (folderValue) => {
141
+ if (!folderValue) return null;
142
+ const folder = normalizeWorkspaceFolder(folderValue);
143
+ if (!folder) return null;
144
+ return {
145
+ workspaceFolder: folder,
146
+ workspaceKey: `folder:${folder}`,
147
+ workspaceLabel: path.basename(folder) || folder,
148
+ workspaceUri: null
149
+ };
150
+ };
151
+ var workspaceFromUri = (uri) => {
152
+ if (!uri) return null;
153
+ const workspace = workspaceFromFolder(uri);
154
+ if (!workspace) return null;
155
+ return {
156
+ ...workspace,
157
+ workspaceUri: uri
158
+ };
159
+ };
160
+ var parseWorkspaceInfo = (field) => {
161
+ const fields = nestedFields(field);
162
+ return workspaceFromUri(fieldString(fields, 1) ?? fieldString(fields, 2));
163
+ };
164
+ var parseContextWorkspaceInfo = (field) => {
165
+ const fields = nestedFields(field);
166
+ const directUri = fieldString(fields, 7);
167
+ if (directUri) return workspaceFromUri(directUri);
168
+ return parseWorkspaceInfo(firstField(fields, 1));
169
+ };
170
+ var parseSummaryEntry = (entryField, summaryPath) => {
171
+ try {
172
+ const entryFields = nestedFields(entryField);
173
+ const conversationId = fieldString(entryFields, 1);
174
+ const summaryBytes = firstField(entryFields, 2);
175
+ if (!conversationId || !summaryBytes) return null;
176
+ const summaryFields = nestedFields(summaryBytes);
177
+ return {
178
+ ...parseWorkspaceInfo(firstField(summaryFields, 9)) ?? parseContextWorkspaceInfo(firstField(summaryFields, 17)) ?? UNKNOWN_WORKSPACE,
179
+ conversationId,
180
+ createdAtMs: parseTimestampMs(firstField(summaryFields, 7)),
181
+ indexedItemCount: fieldNumberValue(summaryFields, 2),
182
+ lastUpdatedAtMs: parseTimestampMs(firstField(summaryFields, 3)),
183
+ summaryPath,
184
+ title: cleanTitle(fieldString(summaryFields, 1), conversationId)
185
+ };
186
+ } catch {
187
+ return null;
188
+ }
189
+ };
190
+ var readAntigravitySummaryIndex = async (summaryPath) => {
191
+ if (!await pathExists(summaryPath)) return [];
192
+ try {
193
+ return parseProtoFields(new Uint8Array(await Bun.file(summaryPath).arrayBuffer())).filter((field) => field.fieldNumber === 1).map((field) => parseSummaryEntry(field, summaryPath)).filter((entry) => entry !== null);
194
+ } catch {
195
+ return [];
196
+ }
197
+ };
198
+ var preferConversationFile = (current, candidate) => {
199
+ if (!current) return candidate;
200
+ if (candidate.mtimeMs !== current.mtimeMs) return candidate.mtimeMs > current.mtimeMs ? candidate : current;
201
+ return candidate.bytes > current.bytes ? candidate : current;
202
+ };
203
+ var readConversationFileCandidate = async (root, conversationDir, entry) => {
204
+ if (!entry.isFile() || !entry.name.endsWith(".pb")) return null;
205
+ const conversationId = entry.name.slice(0, -3);
206
+ const filePath = path.join(conversationDir, entry.name);
207
+ try {
208
+ const info = await stat(filePath);
209
+ return {
210
+ conversationId,
211
+ file: {
212
+ bytes: info.size,
213
+ mtimeMs: info.mtimeMs,
214
+ path: filePath,
215
+ root
216
+ }
217
+ };
218
+ } catch (error) {
219
+ if (isFileMissingError(error)) return null;
220
+ throw error;
221
+ }
222
+ };
223
+ var readConversationFiles = async (roots) => {
224
+ const files = /* @__PURE__ */ new Map();
225
+ for (const root of roots) {
226
+ const conversationDir = getAntigravityConversationDir(root);
227
+ let entries = [];
228
+ try {
229
+ entries = await readdir(conversationDir, { withFileTypes: true });
230
+ } catch {
231
+ continue;
232
+ }
233
+ for (const entry of entries) {
234
+ const candidate = await readConversationFileCandidate(root, conversationDir, entry);
235
+ if (candidate) files.set(candidate.conversationId, preferConversationFile(files.get(candidate.conversationId), candidate.file));
236
+ }
237
+ }
238
+ return files;
239
+ };
240
+ var readArtifactMetadata = async (markdownPath) => {
241
+ try {
242
+ const data = await Bun.file(`${markdownPath}.metadata.json`).json();
243
+ const updatedAt = typeof data.updatedAt === "string" ? Date.parse(data.updatedAt) : NaN;
244
+ return {
245
+ artifactType: typeof data.artifactType === "string" ? data.artifactType : null,
246
+ summary: typeof data.summary === "string" ? data.summary : null,
247
+ updatedAtMs: Number.isFinite(updatedAt) ? updatedAt : null
248
+ };
249
+ } catch {
250
+ return {
251
+ artifactType: null,
252
+ summary: null,
253
+ updatedAtMs: null
254
+ };
255
+ }
256
+ };
257
+ var readArtifactCandidate = async (root, artifactPath, fileName) => {
258
+ try {
259
+ const [info, metadata] = await Promise.all([stat(artifactPath), readArtifactMetadata(artifactPath)]);
260
+ return {
261
+ artifactType: metadata.artifactType,
262
+ bytes: info.size,
263
+ name: fileName,
264
+ path: artifactPath,
265
+ sourceRoot: root,
266
+ summary: metadata.summary,
267
+ updatedAtMs: metadata.updatedAtMs ?? info.mtimeMs
268
+ };
269
+ } catch (error) {
270
+ if (isFileMissingError(error)) return null;
271
+ throw error;
272
+ }
273
+ };
274
+ var readArtifactsForRoot = async (root) => {
275
+ const brainDir = getAntigravityBrainDir(root);
276
+ let entries = [];
277
+ try {
278
+ entries = await readdir(brainDir, { withFileTypes: true });
279
+ } catch {
280
+ return /* @__PURE__ */ new Map();
281
+ }
282
+ const artifactsByConversation = /* @__PURE__ */ new Map();
283
+ for (const entry of entries) {
284
+ if (!entry.isDirectory()) continue;
285
+ const artifactDir = path.join(brainDir, entry.name);
286
+ const files = await readdir(artifactDir, { withFileTypes: true }).catch(() => []);
287
+ for (const file of files) {
288
+ if (!file.isFile() || !file.name.endsWith(".md")) continue;
289
+ const artifact = await readArtifactCandidate(root, path.join(artifactDir, file.name), file.name);
290
+ if (!artifact) continue;
291
+ const list = artifactsByConversation.get(entry.name) ?? [];
292
+ list.push(artifact);
293
+ artifactsByConversation.set(entry.name, list);
294
+ }
295
+ }
296
+ return artifactsByConversation;
297
+ };
298
+ var mergeArtifactMaps = async (roots) => {
299
+ const merged = /* @__PURE__ */ new Map();
300
+ for (const root of roots) {
301
+ const artifacts = await readArtifactsForRoot(root);
302
+ for (const [conversationId, list] of artifacts) {
303
+ const existing = merged.get(conversationId) ?? [];
304
+ const byName = new Map(existing.map((artifact) => [artifact.name, artifact]));
305
+ for (const artifact of list) if (!byName.has(artifact.name)) byName.set(artifact.name, artifact);
306
+ merged.set(conversationId, [...byName.values()].sort((a, b) => (b.updatedAtMs ?? 0) - (a.updatedAtMs ?? 0) || a.name.localeCompare(b.name)));
307
+ }
308
+ }
309
+ return merged;
310
+ };
311
+ var countJsonlEntries = async (filePath) => {
312
+ try {
313
+ return (await Bun.file(filePath).text()).split(/\r?\n/u).filter((line) => line.trim().length > 0).length;
314
+ } catch {
315
+ return 0;
316
+ }
317
+ };
318
+ var preferTranscriptFile = (current, candidate) => {
319
+ if (!current) return candidate;
320
+ if (candidate.mtimeMs !== current.mtimeMs) return candidate.mtimeMs > current.mtimeMs ? candidate : current;
321
+ if (candidate.source !== current.source) return candidate.source === "overview" ? candidate : current;
322
+ return candidate.entryCount > current.entryCount ? candidate : current;
323
+ };
324
+ var readTranscriptFilesForRoot = async (root) => {
325
+ const brainDir = getAntigravityBrainDir(root);
326
+ let entries = [];
327
+ try {
328
+ entries = await readdir(brainDir, { withFileTypes: true });
329
+ } catch {
330
+ return /* @__PURE__ */ new Map();
331
+ }
332
+ const transcripts = /* @__PURE__ */ new Map();
333
+ for (const entry of entries) {
334
+ if (!entry.isDirectory()) continue;
335
+ const logsDir = path.join(brainDir, entry.name, ".system_generated", "logs");
336
+ for (const candidate of [{
337
+ name: "overview.txt",
338
+ source: "overview"
339
+ }, {
340
+ name: "transcript.jsonl",
341
+ source: "transcript"
342
+ }]) {
343
+ const transcriptPath = path.join(logsDir, candidate.name);
344
+ try {
345
+ const info = await stat(transcriptPath);
346
+ if (!info.isFile()) continue;
347
+ transcripts.set(entry.name, preferTranscriptFile(transcripts.get(entry.name), {
348
+ bytes: info.size,
349
+ entryCount: await countJsonlEntries(transcriptPath),
350
+ mtimeMs: info.mtimeMs,
351
+ path: transcriptPath,
352
+ root,
353
+ source: candidate.source
354
+ }));
355
+ } catch {}
356
+ }
357
+ }
358
+ return transcripts;
359
+ };
360
+ var mergeTranscriptMaps = async (roots) => {
361
+ const merged = /* @__PURE__ */ new Map();
362
+ for (const root of roots) {
363
+ const transcripts = await readTranscriptFilesForRoot(root);
364
+ for (const [conversationId, transcript] of transcripts) merged.set(conversationId, preferTranscriptFile(merged.get(conversationId), transcript));
365
+ }
366
+ return merged;
367
+ };
368
+ var readSummaryEntries = async (roots) => {
369
+ const summaries = /* @__PURE__ */ new Map();
370
+ for (const root of roots) for (const entry of await readAntigravitySummaryIndex(getAntigravitySummaryIndexPath(root))) {
371
+ const existing = summaries.get(entry.conversationId);
372
+ if (!existing || (entry.lastUpdatedAtMs ?? 0) > (existing.lastUpdatedAtMs ?? 0)) summaries.set(entry.conversationId, entry);
373
+ }
374
+ return summaries;
375
+ };
376
+ var maxArtifactUpdatedAt = (artifacts) => {
377
+ const value = Math.max(0, ...artifacts.map((artifact) => artifact.updatedAtMs ?? 0));
378
+ return value > 0 ? value : null;
379
+ };
380
+ var resolveConversationSourceRoot = (file, transcript, artifacts) => {
381
+ return file?.root ?? transcript?.root ?? artifacts[0]?.sourceRoot ?? null;
382
+ };
383
+ var resolveConversationWorkspace = (summary, file, transcript, artifacts) => {
384
+ return summary ?? workspaceFromFolder(resolveConversationSourceRoot(file, transcript, artifacts)) ?? UNKNOWN_WORKSPACE;
385
+ };
386
+ var resolveConversationTranscriptSource = (file, transcript) => {
387
+ return transcript?.source ?? (file?.path ? "safe-storage" : null);
388
+ };
389
+ var resolveConversationLastUpdatedAt = (artifacts, file, summary, transcript) => {
390
+ return summary?.lastUpdatedAtMs ?? transcript?.mtimeMs ?? file?.mtimeMs ?? maxArtifactUpdatedAt(artifacts);
391
+ };
392
+ var toConversation = (conversationId, summary, file, artifacts, transcript) => {
393
+ const fallbackTitle = artifacts[0]?.summary ?? conversationId;
394
+ const artifactBytes = artifacts.reduce((total, artifact) => total + artifact.bytes, 0);
395
+ const workspace = resolveConversationWorkspace(summary, file, transcript, artifacts);
396
+ const lastUpdatedAtMs = resolveConversationLastUpdatedAt(artifacts, file, summary, transcript);
397
+ const sourceRoot = resolveConversationSourceRoot(file, transcript, artifacts);
398
+ return {
399
+ artifactBytes,
400
+ artifactCount: artifacts.length,
401
+ artifacts,
402
+ conversationBytes: file?.bytes ?? 0,
403
+ conversationId,
404
+ conversationMtimeMs: file?.mtimeMs ?? null,
405
+ conversationPath: file?.path ?? null,
406
+ createdAtMs: summary?.createdAtMs ?? null,
407
+ indexedItemCount: summary?.indexedItemCount ?? null,
408
+ lastUpdatedAtMs,
409
+ sourceRoot,
410
+ summaryPath: summary?.summaryPath ?? null,
411
+ title: summary?.title ?? cleanTitle(fallbackTitle, conversationId),
412
+ transcriptBytes: transcript?.bytes ?? 0,
413
+ transcriptEntryCount: transcript?.entryCount ?? 0,
414
+ transcriptPath: transcript?.path ?? null,
415
+ transcriptSource: resolveConversationTranscriptSource(file, transcript),
416
+ workspaceFolder: workspace.workspaceFolder,
417
+ workspaceKey: workspace.workspaceKey,
418
+ workspaceLabel: workspace.workspaceLabel,
419
+ workspaceUri: workspace.workspaceUri
420
+ };
421
+ };
422
+ var listAntigravityConversations = async (roots = resolveAntigravityRoots()) => {
423
+ const [summaries, conversationFiles, artifacts, transcripts] = await Promise.all([
424
+ readSummaryEntries(roots),
425
+ readConversationFiles(roots),
426
+ mergeArtifactMaps(roots),
427
+ mergeTranscriptMaps(roots)
428
+ ]);
429
+ return [...new Set([
430
+ ...summaries.keys(),
431
+ ...conversationFiles.keys(),
432
+ ...artifacts.keys(),
433
+ ...transcripts.keys()
434
+ ])].map((conversationId) => toConversation(conversationId, summaries.get(conversationId), conversationFiles.get(conversationId), artifacts.get(conversationId) ?? [], transcripts.get(conversationId))).sort((a, b) => (b.lastUpdatedAtMs ?? 0) - (a.lastUpdatedAtMs ?? 0) || a.title.localeCompare(b.title));
435
+ };
436
+ var groupAntigravityConversations = (conversations) => {
437
+ const groups = /* @__PURE__ */ new Map();
438
+ for (const conversation of conversations) {
439
+ const current = groups.get(conversation.workspaceKey) ?? {
440
+ artifactCount: 0,
441
+ conversationBytes: 0,
442
+ conversationCount: 0,
443
+ key: conversation.workspaceKey,
444
+ label: conversation.workspaceLabel,
445
+ lastActiveMs: 0,
446
+ transcriptCount: 0,
447
+ uri: conversation.workspaceUri
448
+ };
449
+ current.artifactCount += conversation.artifactCount;
450
+ current.conversationBytes += conversation.conversationBytes;
451
+ current.conversationCount += 1;
452
+ current.lastActiveMs = Math.max(current.lastActiveMs, conversation.lastUpdatedAtMs ?? 0);
453
+ current.transcriptCount += conversation.transcriptEntryCount > 0 ? 1 : 0;
454
+ groups.set(conversation.workspaceKey, current);
455
+ }
456
+ return [...groups.values()].sort((a, b) => b.lastActiveMs - a.lastActiveMs || a.label.localeCompare(b.label));
457
+ };
458
+ var listAntigravityWorkspaceGroups = async (roots = resolveAntigravityRoots()) => {
459
+ return groupAntigravityConversations(await listAntigravityConversations(roots));
460
+ };
461
+ var listAntigravityConversationsForGroup = async (workspaceKey, roots = resolveAntigravityRoots()) => {
462
+ return (await listAntigravityConversations(roots)).filter((conversation) => conversation.workspaceKey === workspaceKey);
463
+ };
464
+ var renderAntigravityArtifactsMarkdown = async (conversation) => {
465
+ if (conversation.artifacts.length === 0) return null;
466
+ const parts = [
467
+ `# ${conversation.title}`,
468
+ "",
469
+ "- exported_from: `antigravity_brain_artifacts`",
470
+ `- conversation_id: \`${conversation.conversationId}\``,
471
+ conversation.workspaceUri ? `- workspace: \`${conversation.workspaceUri}\`` : "",
472
+ ""
473
+ ].filter(Boolean);
474
+ for (const artifact of conversation.artifacts) {
475
+ const body = await Bun.file(artifact.path).text();
476
+ parts.push(`## ${artifact.name}`, "");
477
+ if (artifact.summary) parts.push(`_${artifact.summary}_`, "");
478
+ parts.push(body.trimEnd(), "");
479
+ }
480
+ return `${parts.join("\n").trimEnd()}\n`;
481
+ };
482
+ var parseLogEntries = (content) => {
483
+ return content.split(/\r?\n/u).map((line) => line.trim()).filter(Boolean).map((line) => {
484
+ try {
485
+ return JSON.parse(line);
486
+ } catch {
487
+ return null;
488
+ }
489
+ }).filter((entry) => entry !== null);
490
+ };
491
+ var getString = (value) => typeof value === "string" ? value : null;
492
+ var stripTaggedBlock = (content, tag) => {
493
+ return content.replace(new RegExp(`<${tag}>[\\s\\S]*?<\\/${tag}>`, "gu"), "").trim();
494
+ };
495
+ var extractTaggedBlock = (content, tag) => {
496
+ return new RegExp(`<${tag}>\\s*([\\s\\S]*?)\\s*<\\/${tag}>`, "u").exec(content)?.[1]?.trim() || null;
497
+ };
498
+ var cleanLogContent = (entry) => {
499
+ const content = getString(entry.content);
500
+ if (!content) return "";
501
+ const userRequest = extractTaggedBlock(content, "USER_REQUEST");
502
+ if (userRequest) return userRequest;
503
+ return ["ADDITIONAL_METADATA", "USER_SETTINGS_CHANGE"].reduce((current, tag) => stripTaggedBlock(current, tag), content).replace(/<\/?USER_REQUEST>/gu, "").trim();
504
+ };
505
+ var logEntryHeading = (entry) => {
506
+ const source = getString(entry.source);
507
+ const type = getString(entry.type);
508
+ if (source?.startsWith("USER")) return "User";
509
+ if (source === "MODEL") return "Assistant";
510
+ if (source === "SYSTEM") return "System";
511
+ return type ? `Tool: ${type}` : "Event";
512
+ };
513
+ var renderToolCalls = (toolCalls) => {
514
+ if (!Array.isArray(toolCalls) || toolCalls.length === 0) return [];
515
+ const parts = ["### Tool Calls", ""];
516
+ for (const call of toolCalls) {
517
+ if (!call || typeof call !== "object") continue;
518
+ const { args, name } = call;
519
+ parts.push(`- \`${typeof name === "string" ? name : "unknown"}\``);
520
+ if (args !== void 0) parts.push("", "```json", JSON.stringify(args, null, 2), "```", "");
521
+ }
522
+ return parts;
523
+ };
524
+ var renderLogEntry = (entry) => {
525
+ const heading = logEntryHeading(entry);
526
+ const timestamp = getString(entry.created_at);
527
+ const content = cleanLogContent(entry);
528
+ const thinking = getString(entry.thinking);
529
+ const parts = [`## ${heading}`, ""];
530
+ if (timestamp) parts.push(`_Timestamp: ${timestamp}_`, "");
531
+ if (thinking) parts.push("### Thinking", "", thinking.trim(), "");
532
+ if (content) parts.push(content, "");
533
+ parts.push(...renderToolCalls(entry.tool_calls));
534
+ return parts;
535
+ };
536
+ var renderAntigravityTranscriptMarkdown = async (conversation) => {
537
+ if (!conversation.transcriptPath || !conversation.transcriptSource) return null;
538
+ const entries = parseLogEntries(await Bun.file(conversation.transcriptPath).text());
539
+ if (entries.length === 0) return null;
540
+ const exportedFrom = conversation.transcriptSource === "overview" ? "antigravity_overview_transcript" : "antigravity_jsonl_transcript";
541
+ const parts = [
542
+ `# ${conversation.title}`,
543
+ "",
544
+ `- exported_from: \`${exportedFrom}\``,
545
+ `- conversation_id: \`${conversation.conversationId}\``,
546
+ conversation.workspaceUri ? `- workspace: \`${conversation.workspaceUri}\`` : "",
547
+ ""
548
+ ].filter(Boolean);
549
+ for (const entry of entries) parts.push(...renderLogEntry(entry));
550
+ return `${parts.join("\n").trimEnd()}\n`;
551
+ };
552
+ var renderDecryptedSafeStorageMarkdown = (conversation, content) => {
553
+ const trimmed = content.trim();
554
+ if (!trimmed) return null;
555
+ return [
556
+ `# ${conversation.title}`,
557
+ "",
558
+ "- exported_from: `antigravity_safe_storage_payload`",
559
+ `- conversation_id: \`${conversation.conversationId}\``,
560
+ conversation.workspaceUri ? `- workspace: \`${conversation.workspaceUri}\`` : "",
561
+ "",
562
+ trimmed,
563
+ ""
564
+ ].filter(Boolean).join("\n");
565
+ };
566
+ var renderAntigravityConversationMarkdown = async (conversation, options = {}) => {
567
+ const transcript = await renderAntigravityTranscriptMarkdown(conversation);
568
+ if (transcript) return transcript;
569
+ if (options.keychainSecret && conversation.conversationPath) {
570
+ const decrypted = decryptAntigravitySafeStoragePayload(Buffer.from(await Bun.file(conversation.conversationPath).arrayBuffer()), options.keychainSecret);
571
+ if (decrypted) return renderDecryptedSafeStorageMarkdown(conversation, decrypted);
572
+ }
573
+ return null;
574
+ };
575
+ //#endregion
576
+ export { listAntigravityConversations, listAntigravityConversationsForGroup, listAntigravityWorkspaceGroups, renderAntigravityArtifactsMarkdown, renderAntigravityConversationMarkdown };
@@ -0,0 +1,126 @@
1
+ import { createDecipheriv, pbkdf2Sync } from "node:crypto";
2
+ import { execFile } from "node:child_process";
3
+ import { promisify } from "node:util";
4
+ //#region ../../src/lib/antigravity-keychain.ts
5
+ var ANTIGRAVITY_KEYCHAIN_SERVICE = "Antigravity Safe Storage";
6
+ var ANTIGRAVITY_KEYCHAIN_ACCOUNT = "Antigravity Key";
7
+ var execFileAsync = promisify(execFile);
8
+ var SAFE_STORAGE_SALT = "saltysalt";
9
+ var SAFE_STORAGE_ITERATIONS = 1003;
10
+ var SAFE_STORAGE_KEY_LENGTH = 16;
11
+ var SAFE_STORAGE_IV = Buffer.alloc(16, 32);
12
+ var cachedKeychainSecret = null;
13
+ var lastKeychainError = null;
14
+ var deriveAntigravitySafeStorageKey = (keychainSecret) => {
15
+ return pbkdf2Sync(keychainSecret, SAFE_STORAGE_SALT, SAFE_STORAGE_ITERATIONS, SAFE_STORAGE_KEY_LENGTH, "sha1");
16
+ };
17
+ var parseBufferJson = (value) => {
18
+ if (!value || typeof value !== "object") return null;
19
+ const data = value.data;
20
+ if (!Array.isArray(data) || data.some((entry) => typeof entry !== "number")) return null;
21
+ return Buffer.from(data);
22
+ };
23
+ var normalizeEncryptedPayload = (payload) => {
24
+ if (payload instanceof Buffer) return payload;
25
+ if (payload instanceof Uint8Array) return Buffer.from(payload);
26
+ const trimmed = payload.trim();
27
+ if (trimmed.startsWith("{")) try {
28
+ return parseBufferJson(JSON.parse(trimmed));
29
+ } catch {
30
+ return null;
31
+ }
32
+ return Buffer.from(payload, "binary");
33
+ };
34
+ var hasSafeStoragePrefix = (payload) => {
35
+ const prefix = payload.subarray(0, 3).toString("ascii");
36
+ return prefix === "v10" || prefix === "v11";
37
+ };
38
+ var isReadableUtf8 = (value) => {
39
+ if (value.includes("�")) return false;
40
+ const printable = [...value].filter((char) => {
41
+ const code = char.charCodeAt(0);
42
+ return code === 9 || code === 10 || code === 13 || code >= 32;
43
+ }).length;
44
+ return value.length === 0 || printable / value.length > .95;
45
+ };
46
+ var decryptWithKey = (encrypted, key) => {
47
+ const ciphertext = hasSafeStoragePrefix(encrypted) ? encrypted.subarray(3) : encrypted;
48
+ if (ciphertext.length === 0 || ciphertext.length % 16 !== 0) return null;
49
+ try {
50
+ const decipher = createDecipheriv("aes-128-cbc", key, SAFE_STORAGE_IV);
51
+ const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
52
+ return isReadableUtf8(decrypted) ? decrypted : null;
53
+ } catch {
54
+ return null;
55
+ }
56
+ };
57
+ var decryptAntigravitySafeStoragePayload = (payload, keychainSecret) => {
58
+ const encrypted = normalizeEncryptedPayload(payload);
59
+ if (!encrypted) return null;
60
+ const keyAttempts = [deriveAntigravitySafeStorageKey(keychainSecret)];
61
+ if (/^[A-Za-z0-9+/]+={0,2}$/u.test(keychainSecret)) keyAttempts.push(deriveAntigravitySafeStorageKey(Buffer.from(keychainSecret, "base64")));
62
+ for (const key of keyAttempts) {
63
+ const decrypted = decryptWithKey(encrypted, key);
64
+ if (decrypted !== null) return decrypted;
65
+ }
66
+ return null;
67
+ };
68
+ var getAntigravityDecryptionState = ({ cachedSecret = cachedKeychainSecret, lastError = lastKeychainError, platform = process.platform } = {}) => {
69
+ if (platform !== "darwin") return {
70
+ canRequestAccess: false,
71
+ error: null,
72
+ isUnlocked: false,
73
+ keychainAccount: ANTIGRAVITY_KEYCHAIN_ACCOUNT,
74
+ keychainService: ANTIGRAVITY_KEYCHAIN_SERVICE,
75
+ platform,
76
+ provider: "unsupported",
77
+ status: "unsupported"
78
+ };
79
+ if (cachedSecret) return {
80
+ canRequestAccess: true,
81
+ error: null,
82
+ isUnlocked: true,
83
+ keychainAccount: ANTIGRAVITY_KEYCHAIN_ACCOUNT,
84
+ keychainService: ANTIGRAVITY_KEYCHAIN_SERVICE,
85
+ platform,
86
+ provider: "keychain",
87
+ status: "unlocked"
88
+ };
89
+ return {
90
+ canRequestAccess: true,
91
+ error: lastError,
92
+ isUnlocked: false,
93
+ keychainAccount: ANTIGRAVITY_KEYCHAIN_ACCOUNT,
94
+ keychainService: ANTIGRAVITY_KEYCHAIN_SERVICE,
95
+ platform,
96
+ provider: "keychain",
97
+ status: lastError ? "error" : "locked"
98
+ };
99
+ };
100
+ var getCachedAntigravityKeychainSecret = () => cachedKeychainSecret;
101
+ var readAntigravityKeychainSecret = async () => {
102
+ if (process.platform !== "darwin") throw new Error("Antigravity Keychain access is only available on macOS.");
103
+ const { stdout } = await execFileAsync("security", [
104
+ "find-generic-password",
105
+ "-s",
106
+ ANTIGRAVITY_KEYCHAIN_SERVICE,
107
+ "-a",
108
+ ANTIGRAVITY_KEYCHAIN_ACCOUNT,
109
+ "-w"
110
+ ]);
111
+ const secret = stdout.trim();
112
+ if (!secret) throw new Error(`No secret was returned for ${ANTIGRAVITY_KEYCHAIN_SERVICE}.`);
113
+ return secret;
114
+ };
115
+ var unlockAntigravityDecryption = async () => {
116
+ try {
117
+ cachedKeychainSecret = await readAntigravityKeychainSecret();
118
+ lastKeychainError = null;
119
+ } catch (error) {
120
+ cachedKeychainSecret = null;
121
+ lastKeychainError = error instanceof Error ? error.message : String(error);
122
+ }
123
+ return getAntigravityDecryptionState();
124
+ };
125
+ //#endregion
126
+ export { decryptAntigravitySafeStoragePayload, getAntigravityDecryptionState, getCachedAntigravityKeychainSecret, unlockAntigravityDecryption };