opencode-antigravity-auth-mf 1.3.0-1

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 (195) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +630 -0
  3. package/dist/index.d.ts +4 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +3 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/src/antigravity/oauth.d.ts +31 -0
  8. package/dist/src/antigravity/oauth.d.ts.map +1 -0
  9. package/dist/src/antigravity/oauth.js +168 -0
  10. package/dist/src/antigravity/oauth.js.map +1 -0
  11. package/dist/src/constants.d.ts +99 -0
  12. package/dist/src/constants.d.ts.map +1 -0
  13. package/dist/src/constants.js +135 -0
  14. package/dist/src/constants.js.map +1 -0
  15. package/dist/src/hooks/auto-update-checker/cache.d.ts +3 -0
  16. package/dist/src/hooks/auto-update-checker/cache.d.ts.map +1 -0
  17. package/dist/src/hooks/auto-update-checker/cache.js +71 -0
  18. package/dist/src/hooks/auto-update-checker/cache.js.map +1 -0
  19. package/dist/src/hooks/auto-update-checker/checker.d.ts +16 -0
  20. package/dist/src/hooks/auto-update-checker/checker.d.ts.map +1 -0
  21. package/dist/src/hooks/auto-update-checker/checker.js +237 -0
  22. package/dist/src/hooks/auto-update-checker/checker.js.map +1 -0
  23. package/dist/src/hooks/auto-update-checker/constants.d.ts +9 -0
  24. package/dist/src/hooks/auto-update-checker/constants.d.ts.map +1 -0
  25. package/dist/src/hooks/auto-update-checker/constants.js +23 -0
  26. package/dist/src/hooks/auto-update-checker/constants.js.map +1 -0
  27. package/dist/src/hooks/auto-update-checker/index.d.ts +34 -0
  28. package/dist/src/hooks/auto-update-checker/index.d.ts.map +1 -0
  29. package/dist/src/hooks/auto-update-checker/index.js +125 -0
  30. package/dist/src/hooks/auto-update-checker/index.js.map +1 -0
  31. package/dist/src/hooks/auto-update-checker/types.d.ts +25 -0
  32. package/dist/src/hooks/auto-update-checker/types.d.ts.map +1 -0
  33. package/dist/src/hooks/auto-update-checker/types.js +1 -0
  34. package/dist/src/hooks/auto-update-checker/types.js.map +1 -0
  35. package/dist/src/plugin/accounts.d.ts +86 -0
  36. package/dist/src/plugin/accounts.d.ts.map +1 -0
  37. package/dist/src/plugin/accounts.js +609 -0
  38. package/dist/src/plugin/accounts.js.map +1 -0
  39. package/dist/src/plugin/auth.d.ts +21 -0
  40. package/dist/src/plugin/auth.d.ts.map +1 -0
  41. package/dist/src/plugin/auth.js +46 -0
  42. package/dist/src/plugin/auth.js.map +1 -0
  43. package/dist/src/plugin/cache/index.d.ts +5 -0
  44. package/dist/src/plugin/cache/index.d.ts.map +1 -0
  45. package/dist/src/plugin/cache/index.js +5 -0
  46. package/dist/src/plugin/cache/index.js.map +1 -0
  47. package/dist/src/plugin/cache/signature-cache.d.ts +111 -0
  48. package/dist/src/plugin/cache/signature-cache.d.ts.map +1 -0
  49. package/dist/src/plugin/cache/signature-cache.js +375 -0
  50. package/dist/src/plugin/cache/signature-cache.js.map +1 -0
  51. package/dist/src/plugin/cache.d.ts +44 -0
  52. package/dist/src/plugin/cache.d.ts.map +1 -0
  53. package/dist/src/plugin/cache.js +200 -0
  54. package/dist/src/plugin/cache.js.map +1 -0
  55. package/dist/src/plugin/cli.d.ts +19 -0
  56. package/dist/src/plugin/cli.d.ts.map +1 -0
  57. package/dist/src/plugin/cli.js +59 -0
  58. package/dist/src/plugin/cli.js.map +1 -0
  59. package/dist/src/plugin/config/index.d.ts +16 -0
  60. package/dist/src/plugin/config/index.d.ts.map +1 -0
  61. package/dist/src/plugin/config/index.js +16 -0
  62. package/dist/src/plugin/config/index.js.map +1 -0
  63. package/dist/src/plugin/config/loader.d.ts +37 -0
  64. package/dist/src/plugin/config/loader.d.ts.map +1 -0
  65. package/dist/src/plugin/config/loader.js +206 -0
  66. package/dist/src/plugin/config/loader.js.map +1 -0
  67. package/dist/src/plugin/config/schema.d.ts +411 -0
  68. package/dist/src/plugin/config/schema.d.ts.map +1 -0
  69. package/dist/src/plugin/config/schema.js +339 -0
  70. package/dist/src/plugin/config/schema.js.map +1 -0
  71. package/dist/src/plugin/core/streaming/index.d.ts +3 -0
  72. package/dist/src/plugin/core/streaming/index.d.ts.map +1 -0
  73. package/dist/src/plugin/core/streaming/index.js +3 -0
  74. package/dist/src/plugin/core/streaming/index.js.map +1 -0
  75. package/dist/src/plugin/core/streaming/transformer.d.ts +10 -0
  76. package/dist/src/plugin/core/streaming/transformer.d.ts.map +1 -0
  77. package/dist/src/plugin/core/streaming/transformer.js +255 -0
  78. package/dist/src/plugin/core/streaming/transformer.js.map +1 -0
  79. package/dist/src/plugin/core/streaming/types.d.ts +35 -0
  80. package/dist/src/plugin/core/streaming/types.d.ts.map +1 -0
  81. package/dist/src/plugin/core/streaming/types.js +1 -0
  82. package/dist/src/plugin/core/streaming/types.js.map +1 -0
  83. package/dist/src/plugin/debug.d.ts +68 -0
  84. package/dist/src/plugin/debug.d.ts.map +1 -0
  85. package/dist/src/plugin/debug.js +325 -0
  86. package/dist/src/plugin/debug.js.map +1 -0
  87. package/dist/src/plugin/errors.d.ts +28 -0
  88. package/dist/src/plugin/errors.d.ts.map +1 -0
  89. package/dist/src/plugin/errors.js +42 -0
  90. package/dist/src/plugin/errors.js.map +1 -0
  91. package/dist/src/plugin/image-saver.d.ts +25 -0
  92. package/dist/src/plugin/image-saver.d.ts.map +1 -0
  93. package/dist/src/plugin/image-saver.js +86 -0
  94. package/dist/src/plugin/image-saver.js.map +1 -0
  95. package/dist/src/plugin/logger.d.ts +54 -0
  96. package/dist/src/plugin/logger.d.ts.map +1 -0
  97. package/dist/src/plugin/logger.js +120 -0
  98. package/dist/src/plugin/logger.js.map +1 -0
  99. package/dist/src/plugin/project.d.ts +33 -0
  100. package/dist/src/plugin/project.d.ts.map +1 -0
  101. package/dist/src/plugin/project.js +234 -0
  102. package/dist/src/plugin/project.js.map +1 -0
  103. package/dist/src/plugin/recovery/constants.d.ts +22 -0
  104. package/dist/src/plugin/recovery/constants.d.ts.map +1 -0
  105. package/dist/src/plugin/recovery/constants.js +43 -0
  106. package/dist/src/plugin/recovery/constants.js.map +1 -0
  107. package/dist/src/plugin/recovery/index.d.ts +12 -0
  108. package/dist/src/plugin/recovery/index.d.ts.map +1 -0
  109. package/dist/src/plugin/recovery/index.js +12 -0
  110. package/dist/src/plugin/recovery/index.js.map +1 -0
  111. package/dist/src/plugin/recovery/storage.d.ts +24 -0
  112. package/dist/src/plugin/recovery/storage.d.ts.map +1 -0
  113. package/dist/src/plugin/recovery/storage.js +354 -0
  114. package/dist/src/plugin/recovery/storage.js.map +1 -0
  115. package/dist/src/plugin/recovery/types.d.ts +116 -0
  116. package/dist/src/plugin/recovery/types.d.ts.map +1 -0
  117. package/dist/src/plugin/recovery/types.js +6 -0
  118. package/dist/src/plugin/recovery/types.js.map +1 -0
  119. package/dist/src/plugin/recovery.d.ts +61 -0
  120. package/dist/src/plugin/recovery.d.ts.map +1 -0
  121. package/dist/src/plugin/recovery.js +376 -0
  122. package/dist/src/plugin/recovery.js.map +1 -0
  123. package/dist/src/plugin/refresh-queue.d.ts +101 -0
  124. package/dist/src/plugin/refresh-queue.d.ts.map +1 -0
  125. package/dist/src/plugin/refresh-queue.js +244 -0
  126. package/dist/src/plugin/refresh-queue.js.map +1 -0
  127. package/dist/src/plugin/request-helpers.d.ts +278 -0
  128. package/dist/src/plugin/request-helpers.d.ts.map +1 -0
  129. package/dist/src/plugin/request-helpers.js +2268 -0
  130. package/dist/src/plugin/request-helpers.js.map +1 -0
  131. package/dist/src/plugin/request.d.ts +91 -0
  132. package/dist/src/plugin/request.d.ts.map +1 -0
  133. package/dist/src/plugin/request.js +1302 -0
  134. package/dist/src/plugin/request.js.map +1 -0
  135. package/dist/src/plugin/rotation.d.ts +168 -0
  136. package/dist/src/plugin/rotation.d.ts.map +1 -0
  137. package/dist/src/plugin/rotation.js +302 -0
  138. package/dist/src/plugin/rotation.js.map +1 -0
  139. package/dist/src/plugin/server.d.ts +23 -0
  140. package/dist/src/plugin/server.d.ts.map +1 -0
  141. package/dist/src/plugin/server.js +324 -0
  142. package/dist/src/plugin/server.js.map +1 -0
  143. package/dist/src/plugin/storage.d.ts +92 -0
  144. package/dist/src/plugin/storage.d.ts.map +1 -0
  145. package/dist/src/plugin/storage.js +417 -0
  146. package/dist/src/plugin/storage.js.map +1 -0
  147. package/dist/src/plugin/stores/signature-store.d.ts +5 -0
  148. package/dist/src/plugin/stores/signature-store.d.ts.map +1 -0
  149. package/dist/src/plugin/stores/signature-store.js +25 -0
  150. package/dist/src/plugin/stores/signature-store.js.map +1 -0
  151. package/dist/src/plugin/thinking-recovery.d.ts +90 -0
  152. package/dist/src/plugin/thinking-recovery.d.ts.map +1 -0
  153. package/dist/src/plugin/thinking-recovery.js +316 -0
  154. package/dist/src/plugin/thinking-recovery.js.map +1 -0
  155. package/dist/src/plugin/token.d.ts +19 -0
  156. package/dist/src/plugin/token.d.ts.map +1 -0
  157. package/dist/src/plugin/token.js +128 -0
  158. package/dist/src/plugin/token.js.map +1 -0
  159. package/dist/src/plugin/transform/claude.d.ts +80 -0
  160. package/dist/src/plugin/transform/claude.d.ts.map +1 -0
  161. package/dist/src/plugin/transform/claude.js +265 -0
  162. package/dist/src/plugin/transform/claude.js.map +1 -0
  163. package/dist/src/plugin/transform/cross-model-sanitizer.d.ts +35 -0
  164. package/dist/src/plugin/transform/cross-model-sanitizer.d.ts.map +1 -0
  165. package/dist/src/plugin/transform/cross-model-sanitizer.js +225 -0
  166. package/dist/src/plugin/transform/cross-model-sanitizer.js.map +1 -0
  167. package/dist/src/plugin/transform/gemini.d.ts +112 -0
  168. package/dist/src/plugin/transform/gemini.d.ts.map +1 -0
  169. package/dist/src/plugin/transform/gemini.js +409 -0
  170. package/dist/src/plugin/transform/gemini.js.map +1 -0
  171. package/dist/src/plugin/transform/index.d.ts +15 -0
  172. package/dist/src/plugin/transform/index.d.ts.map +1 -0
  173. package/dist/src/plugin/transform/index.js +14 -0
  174. package/dist/src/plugin/transform/index.js.map +1 -0
  175. package/dist/src/plugin/transform/model-resolver.d.ts +101 -0
  176. package/dist/src/plugin/transform/model-resolver.d.ts.map +1 -0
  177. package/dist/src/plugin/transform/model-resolver.js +356 -0
  178. package/dist/src/plugin/transform/model-resolver.js.map +1 -0
  179. package/dist/src/plugin/transform/types.d.ts +106 -0
  180. package/dist/src/plugin/transform/types.d.ts.map +1 -0
  181. package/dist/src/plugin/transform/types.js +1 -0
  182. package/dist/src/plugin/transform/types.js.map +1 -0
  183. package/dist/src/plugin/types.d.ts +96 -0
  184. package/dist/src/plugin/types.d.ts.map +1 -0
  185. package/dist/src/plugin/types.js +1 -0
  186. package/dist/src/plugin/types.js.map +1 -0
  187. package/dist/src/plugin/usage-reporter.d.ts +23 -0
  188. package/dist/src/plugin/usage-reporter.d.ts.map +1 -0
  189. package/dist/src/plugin/usage-reporter.js +43 -0
  190. package/dist/src/plugin/usage-reporter.js.map +1 -0
  191. package/dist/src/plugin.d.ts +8 -0
  192. package/dist/src/plugin.d.ts.map +1 -0
  193. package/dist/src/plugin.js +1708 -0
  194. package/dist/src/plugin.js.map +1 -0
  195. package/package.json +67 -0
@@ -0,0 +1,417 @@
1
+ import { promises as fs } from "node:fs";
2
+ import { existsSync, readFileSync, writeFileSync, appendFileSync, } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { homedir } from "node:os";
5
+ import { randomBytes } from "node:crypto";
6
+ import lockfile from "proper-lockfile";
7
+ import { createLogger } from "./logger";
8
+ const log = createLogger("storage");
9
+ /**
10
+ * Files/directories that should be gitignored in the config directory.
11
+ * These contain sensitive data or machine-specific state.
12
+ */
13
+ export const GITIGNORE_ENTRIES = [
14
+ ".gitignore",
15
+ "antigravity-accounts.json",
16
+ "antigravity-signature-cache.json",
17
+ "antigravity-logs/",
18
+ ];
19
+ /**
20
+ * Ensures a .gitignore file exists in the config directory with entries
21
+ * for sensitive files. Creates the file if missing, or appends missing
22
+ * entries if it already exists.
23
+ */
24
+ export async function ensureGitignore(configDir) {
25
+ const gitignorePath = join(configDir, ".gitignore");
26
+ try {
27
+ let content;
28
+ let existingLines = [];
29
+ try {
30
+ content = await fs.readFile(gitignorePath, "utf-8");
31
+ existingLines = content.split("\n").map((line) => line.trim());
32
+ }
33
+ catch (error) {
34
+ if (error.code !== "ENOENT") {
35
+ return;
36
+ }
37
+ content = "";
38
+ }
39
+ const missingEntries = GITIGNORE_ENTRIES.filter((entry) => !existingLines.includes(entry));
40
+ if (missingEntries.length === 0) {
41
+ return;
42
+ }
43
+ if (content === "") {
44
+ await fs.writeFile(gitignorePath, missingEntries.join("\n") + "\n", "utf-8");
45
+ log.info("Created .gitignore in config directory");
46
+ }
47
+ else {
48
+ const suffix = content.endsWith("\n") ? "" : "\n";
49
+ await fs.appendFile(gitignorePath, suffix + missingEntries.join("\n") + "\n", "utf-8");
50
+ log.info("Updated .gitignore with missing entries", {
51
+ added: missingEntries,
52
+ });
53
+ }
54
+ }
55
+ catch {
56
+ // Non-critical feature
57
+ }
58
+ }
59
+ /**
60
+ * Synchronous version of ensureGitignore for use in sync code paths.
61
+ */
62
+ export function ensureGitignoreSync(configDir) {
63
+ const gitignorePath = join(configDir, ".gitignore");
64
+ try {
65
+ let content;
66
+ let existingLines = [];
67
+ if (existsSync(gitignorePath)) {
68
+ content = readFileSync(gitignorePath, "utf-8");
69
+ existingLines = content.split("\n").map((line) => line.trim());
70
+ }
71
+ else {
72
+ content = "";
73
+ }
74
+ const missingEntries = GITIGNORE_ENTRIES.filter((entry) => !existingLines.includes(entry));
75
+ if (missingEntries.length === 0) {
76
+ return;
77
+ }
78
+ if (content === "") {
79
+ writeFileSync(gitignorePath, missingEntries.join("\n") + "\n", "utf-8");
80
+ log.info("Created .gitignore in config directory");
81
+ }
82
+ else {
83
+ const suffix = content.endsWith("\n") ? "" : "\n";
84
+ appendFileSync(gitignorePath, suffix + missingEntries.join("\n") + "\n", "utf-8");
85
+ log.info("Updated .gitignore with missing entries", {
86
+ added: missingEntries,
87
+ });
88
+ }
89
+ }
90
+ catch {
91
+ // Non-critical feature
92
+ }
93
+ }
94
+ function getConfigDir() {
95
+ const platform = process.platform;
96
+ if (platform === "win32") {
97
+ return join(process.env.APPDATA || join(homedir(), "AppData", "Roaming"), "opencode");
98
+ }
99
+ const xdgConfig = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
100
+ return join(xdgConfig, "opencode");
101
+ }
102
+ export function getStoragePath() {
103
+ return join(getConfigDir(), "antigravity-accounts.json");
104
+ }
105
+ const LOCK_OPTIONS = {
106
+ stale: 10000,
107
+ retries: {
108
+ retries: 5,
109
+ minTimeout: 100,
110
+ maxTimeout: 1000,
111
+ factor: 2,
112
+ },
113
+ };
114
+ async function ensureFileExists(path) {
115
+ try {
116
+ await fs.access(path);
117
+ }
118
+ catch {
119
+ await fs.mkdir(dirname(path), { recursive: true });
120
+ await fs.writeFile(path, JSON.stringify({ version: 3, accounts: [], activeIndex: 0 }, null, 2), "utf-8");
121
+ }
122
+ }
123
+ async function withFileLock(path, fn) {
124
+ await ensureFileExists(path);
125
+ let release = null;
126
+ try {
127
+ release = await lockfile.lock(path, LOCK_OPTIONS);
128
+ return await fn();
129
+ }
130
+ finally {
131
+ if (release) {
132
+ try {
133
+ await release();
134
+ }
135
+ catch (unlockError) {
136
+ log.warn("Failed to release lock", { error: String(unlockError) });
137
+ }
138
+ }
139
+ }
140
+ }
141
+ function mergeAccountStorage(existing, incoming) {
142
+ const accountMap = new Map();
143
+ for (const acc of existing.accounts) {
144
+ if (acc.refreshToken) {
145
+ accountMap.set(acc.refreshToken, acc);
146
+ }
147
+ }
148
+ for (const acc of incoming.accounts) {
149
+ if (acc.refreshToken) {
150
+ const existingAcc = accountMap.get(acc.refreshToken);
151
+ if (existingAcc) {
152
+ accountMap.set(acc.refreshToken, {
153
+ ...existingAcc,
154
+ ...acc,
155
+ // Preserve manually configured projectId/managedProjectId if not in incoming
156
+ projectId: acc.projectId ?? existingAcc.projectId,
157
+ managedProjectId: acc.managedProjectId ?? existingAcc.managedProjectId,
158
+ rateLimitResetTimes: {
159
+ ...existingAcc.rateLimitResetTimes,
160
+ ...acc.rateLimitResetTimes,
161
+ },
162
+ lastUsed: Math.max(existingAcc.lastUsed || 0, acc.lastUsed || 0),
163
+ });
164
+ }
165
+ else {
166
+ accountMap.set(acc.refreshToken, acc);
167
+ }
168
+ }
169
+ }
170
+ return {
171
+ version: 3,
172
+ accounts: Array.from(accountMap.values()),
173
+ activeIndex: incoming.activeIndex,
174
+ activeIndexByFamily: incoming.activeIndexByFamily,
175
+ };
176
+ }
177
+ export function deduplicateAccountsByEmail(accounts) {
178
+ const emailToNewestIndex = new Map();
179
+ const indicesToKeep = new Set();
180
+ // First pass: find the newest account for each email (by lastUsed, then addedAt)
181
+ for (let i = 0; i < accounts.length; i++) {
182
+ const acc = accounts[i];
183
+ if (!acc)
184
+ continue;
185
+ if (!acc.email) {
186
+ // No email - keep this account (can't deduplicate without email)
187
+ indicesToKeep.add(i);
188
+ continue;
189
+ }
190
+ const existingIndex = emailToNewestIndex.get(acc.email);
191
+ if (existingIndex === undefined) {
192
+ emailToNewestIndex.set(acc.email, i);
193
+ continue;
194
+ }
195
+ // Compare to find which is newer
196
+ const existing = accounts[existingIndex];
197
+ if (!existing) {
198
+ emailToNewestIndex.set(acc.email, i);
199
+ continue;
200
+ }
201
+ // Prefer higher lastUsed, then higher addedAt
202
+ // Compare fields separately to avoid integer overflow with large timestamps
203
+ const currLastUsed = acc.lastUsed || 0;
204
+ const existLastUsed = existing.lastUsed || 0;
205
+ const currAddedAt = acc.addedAt || 0;
206
+ const existAddedAt = existing.addedAt || 0;
207
+ const isNewer = currLastUsed > existLastUsed ||
208
+ (currLastUsed === existLastUsed && currAddedAt > existAddedAt);
209
+ if (isNewer) {
210
+ emailToNewestIndex.set(acc.email, i);
211
+ }
212
+ }
213
+ // Add all the newest email-based indices to the keep set
214
+ for (const idx of emailToNewestIndex.values()) {
215
+ indicesToKeep.add(idx);
216
+ }
217
+ // Build the deduplicated list, preserving original order for kept items
218
+ const result = [];
219
+ for (let i = 0; i < accounts.length; i++) {
220
+ if (indicesToKeep.has(i)) {
221
+ const acc = accounts[i];
222
+ if (acc) {
223
+ result.push(acc);
224
+ }
225
+ }
226
+ }
227
+ return result;
228
+ }
229
+ function migrateV1ToV2(v1) {
230
+ return {
231
+ version: 2,
232
+ accounts: v1.accounts.map((acc) => {
233
+ const rateLimitResetTimes = {};
234
+ if (acc.isRateLimited &&
235
+ acc.rateLimitResetTime &&
236
+ acc.rateLimitResetTime > Date.now()) {
237
+ rateLimitResetTimes.claude = acc.rateLimitResetTime;
238
+ rateLimitResetTimes.gemini = acc.rateLimitResetTime;
239
+ }
240
+ return {
241
+ email: acc.email,
242
+ refreshToken: acc.refreshToken,
243
+ projectId: acc.projectId,
244
+ managedProjectId: acc.managedProjectId,
245
+ addedAt: acc.addedAt,
246
+ lastUsed: acc.lastUsed,
247
+ lastSwitchReason: acc.lastSwitchReason,
248
+ rateLimitResetTimes: Object.keys(rateLimitResetTimes).length > 0
249
+ ? rateLimitResetTimes
250
+ : undefined,
251
+ };
252
+ }),
253
+ activeIndex: v1.activeIndex,
254
+ };
255
+ }
256
+ export function migrateV2ToV3(v2) {
257
+ return {
258
+ version: 3,
259
+ accounts: v2.accounts.map((acc) => {
260
+ const rateLimitResetTimes = {};
261
+ if (acc.rateLimitResetTimes?.claude &&
262
+ acc.rateLimitResetTimes.claude > Date.now()) {
263
+ rateLimitResetTimes.claude = acc.rateLimitResetTimes.claude;
264
+ }
265
+ if (acc.rateLimitResetTimes?.gemini &&
266
+ acc.rateLimitResetTimes.gemini > Date.now()) {
267
+ rateLimitResetTimes["gemini-antigravity"] =
268
+ acc.rateLimitResetTimes.gemini;
269
+ }
270
+ return {
271
+ email: acc.email,
272
+ refreshToken: acc.refreshToken,
273
+ projectId: acc.projectId,
274
+ managedProjectId: acc.managedProjectId,
275
+ addedAt: acc.addedAt,
276
+ lastUsed: acc.lastUsed,
277
+ lastSwitchReason: acc.lastSwitchReason,
278
+ rateLimitResetTimes: Object.keys(rateLimitResetTimes).length > 0
279
+ ? rateLimitResetTimes
280
+ : undefined,
281
+ };
282
+ }),
283
+ activeIndex: v2.activeIndex,
284
+ };
285
+ }
286
+ export async function loadAccounts() {
287
+ try {
288
+ const path = getStoragePath();
289
+ const content = await fs.readFile(path, "utf-8");
290
+ const data = JSON.parse(content);
291
+ if (!Array.isArray(data.accounts)) {
292
+ log.warn("Invalid storage format, ignoring");
293
+ return null;
294
+ }
295
+ let storage;
296
+ if (data.version === 1) {
297
+ log.info("Migrating account storage from v1 to v3");
298
+ const v2 = migrateV1ToV2(data);
299
+ storage = migrateV2ToV3(v2);
300
+ try {
301
+ await saveAccounts(storage);
302
+ log.info("Migration to v3 complete");
303
+ }
304
+ catch (saveError) {
305
+ log.warn("Failed to persist migrated storage", {
306
+ error: String(saveError),
307
+ });
308
+ }
309
+ }
310
+ else if (data.version === 2) {
311
+ log.info("Migrating account storage from v2 to v3");
312
+ storage = migrateV2ToV3(data);
313
+ try {
314
+ await saveAccounts(storage);
315
+ log.info("Migration to v3 complete");
316
+ }
317
+ catch (saveError) {
318
+ log.warn("Failed to persist migrated storage", {
319
+ error: String(saveError),
320
+ });
321
+ }
322
+ }
323
+ else if (data.version === 3) {
324
+ storage = data;
325
+ }
326
+ else {
327
+ log.warn("Unknown storage version, ignoring", {
328
+ version: data.version,
329
+ });
330
+ return null;
331
+ }
332
+ // Validate accounts have required fields
333
+ const validAccounts = storage.accounts.filter((a) => {
334
+ return (!!a &&
335
+ typeof a === "object" &&
336
+ typeof a.refreshToken === "string");
337
+ });
338
+ // Deduplicate accounts by email (keeps newest entry for each email)
339
+ const deduplicatedAccounts = deduplicateAccountsByEmail(validAccounts);
340
+ // Clamp activeIndex to valid range after deduplication
341
+ let activeIndex = typeof storage.activeIndex === "number" &&
342
+ Number.isFinite(storage.activeIndex)
343
+ ? storage.activeIndex
344
+ : 0;
345
+ if (deduplicatedAccounts.length > 0) {
346
+ activeIndex = Math.min(activeIndex, deduplicatedAccounts.length - 1);
347
+ activeIndex = Math.max(activeIndex, 0);
348
+ }
349
+ else {
350
+ activeIndex = 0;
351
+ }
352
+ return {
353
+ version: 3,
354
+ accounts: deduplicatedAccounts,
355
+ activeIndex,
356
+ };
357
+ }
358
+ catch (error) {
359
+ const code = error.code;
360
+ if (code === "ENOENT") {
361
+ return null;
362
+ }
363
+ log.error("Failed to load account storage", { error: String(error) });
364
+ return null;
365
+ }
366
+ }
367
+ export async function saveAccounts(storage) {
368
+ const path = getStoragePath();
369
+ const configDir = dirname(path);
370
+ await fs.mkdir(configDir, { recursive: true });
371
+ await ensureGitignore(configDir);
372
+ await withFileLock(path, async () => {
373
+ const existing = await loadAccountsUnsafe();
374
+ const merged = existing ? mergeAccountStorage(existing, storage) : storage;
375
+ const tempPath = `${path}.${randomBytes(6).toString("hex")}.tmp`;
376
+ const content = JSON.stringify(merged, null, 2);
377
+ await fs.writeFile(tempPath, content, "utf-8");
378
+ await fs.rename(tempPath, path);
379
+ });
380
+ }
381
+ async function loadAccountsUnsafe() {
382
+ try {
383
+ const path = getStoragePath();
384
+ const content = await fs.readFile(path, "utf-8");
385
+ const parsed = JSON.parse(content);
386
+ if (parsed.version === 1) {
387
+ return migrateV2ToV3(migrateV1ToV2(parsed));
388
+ }
389
+ if (parsed.version === 2) {
390
+ return migrateV2ToV3(parsed);
391
+ }
392
+ return {
393
+ ...parsed,
394
+ accounts: deduplicateAccountsByEmail(parsed.accounts),
395
+ };
396
+ }
397
+ catch (error) {
398
+ const code = error.code;
399
+ if (code === "ENOENT") {
400
+ return null;
401
+ }
402
+ return null;
403
+ }
404
+ }
405
+ export async function clearAccounts() {
406
+ try {
407
+ const path = getStoragePath();
408
+ await fs.unlink(path);
409
+ }
410
+ catch (error) {
411
+ const code = error.code;
412
+ if (code !== "ENOENT") {
413
+ log.error("Failed to clear account storage", { error: String(error) });
414
+ }
415
+ }
416
+ }
417
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../../src/plugin/storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { SignatureStore, ThoughtBuffer } from '../core/streaming/types';
2
+ export declare function createSignatureStore(): SignatureStore;
3
+ export declare function createThoughtBuffer(): ThoughtBuffer;
4
+ export declare const defaultSignatureStore: SignatureStore;
5
+ //# sourceMappingURL=signature-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signature-store.d.ts","sourceRoot":"","sources":["../../../../src/plugin/stores/signature-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAkB,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7F,wBAAgB,oBAAoB,IAAI,cAAc,CAarD;AAED,wBAAgB,mBAAmB,IAAI,aAAa,CAUnD;AAED,eAAO,MAAM,qBAAqB,gBAAyB,CAAC"}
@@ -0,0 +1,25 @@
1
+ export function createSignatureStore() {
2
+ const store = new Map();
3
+ return {
4
+ get: (key) => store.get(key),
5
+ set: (key, value) => {
6
+ store.set(key, value);
7
+ },
8
+ has: (key) => store.has(key),
9
+ delete: (key) => {
10
+ store.delete(key);
11
+ },
12
+ };
13
+ }
14
+ export function createThoughtBuffer() {
15
+ const buffer = new Map();
16
+ return {
17
+ get: (index) => buffer.get(index),
18
+ set: (index, text) => {
19
+ buffer.set(index, text);
20
+ },
21
+ clear: () => buffer.clear(),
22
+ };
23
+ }
24
+ export const defaultSignatureStore = createSignatureStore();
25
+ //# sourceMappingURL=signature-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signature-store.js","sourceRoot":"","sources":["../../../../src/plugin/stores/signature-store.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,oBAAoB;IAClC,MAAM,KAAK,GAAG,IAAI,GAAG,EAA0B,CAAC;IAEhD,OAAO;QACL,GAAG,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;QACpC,GAAG,EAAE,CAAC,GAAW,EAAE,KAAqB,EAAE,EAAE;YAC1C,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACxB,CAAC;QACD,GAAG,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;QACpC,MAAM,EAAE,CAAC,GAAW,EAAE,EAAE;YACtB,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACpB,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IAEzC,OAAO;QACL,GAAG,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;QACzC,GAAG,EAAE,CAAC,KAAa,EAAE,IAAY,EAAE,EAAE;YACnC,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC1B,CAAC;QACD,KAAK,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE;KAC5B,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,qBAAqB,GAAG,oBAAoB,EAAE,CAAC"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Thinking Recovery Module
3
+ *
4
+ * Minimal implementation for recovering from corrupted thinking state.
5
+ * When Claude's conversation history gets corrupted (thinking blocks stripped/malformed),
6
+ * this module provides a "last resort" recovery by closing the current turn and starting fresh.
7
+ *
8
+ * Philosophy: "Let it crash and start again" - Instead of trying to fix corrupted state,
9
+ * we abandon the corrupted turn and let Claude generate fresh thinking.
10
+ */
11
+ /**
12
+ * Conversation state for thinking mode analysis
13
+ */
14
+ export interface ConversationState {
15
+ /** True if we're in an incomplete tool use loop (ends with functionResponse) */
16
+ inToolLoop: boolean;
17
+ /** Index of first model message in current turn */
18
+ turnStartIdx: number;
19
+ /** Whether the TURN started with thinking */
20
+ turnHasThinking: boolean;
21
+ /** Index of last model message */
22
+ lastModelIdx: number;
23
+ /** Whether last model msg has thinking */
24
+ lastModelHasThinking: boolean;
25
+ /** Whether last model msg has tool calls */
26
+ lastModelHasToolCalls: boolean;
27
+ }
28
+ /**
29
+ * Analyzes conversation state to detect tool use loops and thinking mode issues.
30
+ *
31
+ * Key insight: A "turn" can span multiple assistant messages in a tool-use loop.
32
+ * We need to find the TURN START (first assistant message after last real user message)
33
+ * and check if THAT message had thinking, not just the last assistant message.
34
+ */
35
+ export declare function analyzeConversationState(contents: any[]): ConversationState;
36
+ /**
37
+ * Closes an incomplete tool loop by injecting synthetic messages to start a new turn.
38
+ *
39
+ * This is the "let it crash and start again" recovery mechanism.
40
+ *
41
+ * When we detect:
42
+ * - We're in a tool loop (conversation ends with functionResponse)
43
+ * - The tool call was made WITHOUT thinking (thinking was stripped/corrupted)
44
+ * - We NOW want to enable thinking
45
+ *
46
+ * Instead of trying to fix the corrupted state, we:
47
+ * 1. Strip ALL thinking blocks (removes any corrupted ones)
48
+ * 2. Add synthetic MODEL message to complete the non-thinking turn
49
+ * 3. Add synthetic USER message to start a NEW turn
50
+ *
51
+ * This allows Claude to generate fresh thinking for the new turn.
52
+ */
53
+ export declare function closeToolLoopForThinking(contents: any[]): any[];
54
+ /**
55
+ * Checks if conversation state requires tool loop closure for thinking recovery.
56
+ *
57
+ * Returns true if:
58
+ * - We're in a tool loop (state.inToolLoop)
59
+ * - The turn didn't start with thinking (state.turnHasThinking === false)
60
+ *
61
+ * This is the trigger for the "let it crash and start again" recovery.
62
+ */
63
+ export declare function needsThinkingRecovery(state: ConversationState): boolean;
64
+ /**
65
+ * Detects if a message looks like it was compacted from a thinking-enabled turn.
66
+ *
67
+ * This is a heuristic to distinguish between:
68
+ * - "Never had thinking" (model didn't use thinking mode)
69
+ * - "Thinking was stripped" (context compaction removed thinking blocks)
70
+ *
71
+ * Port of LLM-API-Key-Proxy's _looks_like_compacted_thinking_turn()
72
+ *
73
+ * Heuristics:
74
+ * 1. Has functionCall parts (typical thinking flow produces tool calls)
75
+ * 2. No thinking parts (thought: true)
76
+ * 3. No text content before functionCall (thinking responses usually have text)
77
+ *
78
+ * @param msg - A single message from the conversation
79
+ * @returns true if the message looks like thinking was stripped
80
+ */
81
+ export declare function looksLikeCompactedThinkingTurn(msg: any): boolean;
82
+ /**
83
+ * Checks if any message in the current turn looks like it was compacted.
84
+ *
85
+ * @param contents - Full conversation contents
86
+ * @param turnStartIdx - Index of the first model message in current turn
87
+ * @returns true if any model message in the turn looks compacted
88
+ */
89
+ export declare function hasPossibleCompactedThinking(contents: any[], turnStartIdx: number): boolean;
90
+ //# sourceMappingURL=thinking-recovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thinking-recovery.d.ts","sourceRoot":"","sources":["../../../src/plugin/thinking-recovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,gFAAgF;IAChF,UAAU,EAAE,OAAO,CAAC;IACpB,mDAAmD;IACnD,YAAY,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,eAAe,EAAE,OAAO,CAAC;IACzB,kCAAkC;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,oBAAoB,EAAE,OAAO,CAAC;IAC9B,4CAA4C;IAC5C,qBAAqB,EAAE,OAAO,CAAC;CAChC;AAsFD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,iBAAiB,CAsD3E;AAoED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,GAAG,EAAE,CA8B/D;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAEvE;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CA0ChE;AAED;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,GAAG,EAAE,EACf,YAAY,EAAE,MAAM,GACnB,OAAO,CAWT"}