@steipete/oracle 0.9.0 → 0.10.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 (177) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +61 -48
  3. package/dist/bin/oracle-cli.js +455 -402
  4. package/dist/bin/oracle-mcp.js +2 -2
  5. package/dist/bin/oracle.js +165 -279
  6. package/dist/scripts/agent-send.js +31 -31
  7. package/dist/scripts/check.js +6 -6
  8. package/dist/scripts/debug/extract-chatgpt-response.js +10 -10
  9. package/dist/scripts/docs-list.js +30 -30
  10. package/dist/scripts/git-policy.js +25 -23
  11. package/dist/scripts/run-cli.js +8 -8
  12. package/dist/scripts/runner.js +203 -195
  13. package/dist/scripts/test-browser.js +21 -18
  14. package/dist/scripts/test-remote-chrome.js +20 -20
  15. package/dist/src/bridge/connection.js +18 -18
  16. package/dist/src/bridge/userConfigFile.js +7 -7
  17. package/dist/src/browser/actions/assistantResponse.js +149 -101
  18. package/dist/src/browser/actions/attachmentDataTransfer.js +49 -47
  19. package/dist/src/browser/actions/attachments.js +246 -150
  20. package/dist/src/browser/actions/domEvents.js +2 -2
  21. package/dist/src/browser/actions/modelSelection.js +275 -117
  22. package/dist/src/browser/actions/navigation.js +161 -137
  23. package/dist/src/browser/actions/promptComposer.js +100 -64
  24. package/dist/src/browser/actions/remoteFileTransfer.js +10 -10
  25. package/dist/src/browser/actions/thinkingTime.js +207 -110
  26. package/dist/src/browser/chromeLifecycle.js +62 -60
  27. package/dist/src/browser/config.js +34 -15
  28. package/dist/src/browser/constants.js +17 -12
  29. package/dist/src/browser/cookies.js +19 -19
  30. package/dist/src/browser/detect.js +62 -62
  31. package/dist/src/browser/domDebug.js +1 -1
  32. package/dist/src/browser/index.js +390 -295
  33. package/dist/src/browser/modelStrategy.js +1 -1
  34. package/dist/src/browser/pageActions.js +5 -5
  35. package/dist/src/browser/policies.js +16 -13
  36. package/dist/src/browser/profileState.js +44 -39
  37. package/dist/src/browser/prompt.js +72 -42
  38. package/dist/src/browser/promptSummary.js +5 -5
  39. package/dist/src/browser/providerDomFlow.js +1 -1
  40. package/dist/src/browser/providers/chatgptDomProvider.js +9 -9
  41. package/dist/src/browser/providers/geminiDeepThinkDomProvider.js +51 -42
  42. package/dist/src/browser/providers/index.js +2 -2
  43. package/dist/src/browser/reattach.js +67 -34
  44. package/dist/src/browser/reattachHelpers.js +31 -26
  45. package/dist/src/browser/sessionRunner.js +37 -25
  46. package/dist/src/browser/utils.js +9 -9
  47. package/dist/src/browserMode.js +1 -1
  48. package/dist/src/cli/bridge/claudeConfig.js +16 -16
  49. package/dist/src/cli/bridge/client.js +28 -20
  50. package/dist/src/cli/bridge/codexConfig.js +16 -16
  51. package/dist/src/cli/bridge/doctor.js +47 -39
  52. package/dist/src/cli/bridge/host.js +58 -56
  53. package/dist/src/cli/browserConfig.js +62 -48
  54. package/dist/src/cli/browserDefaults.js +27 -26
  55. package/dist/src/cli/bundleWarnings.js +1 -1
  56. package/dist/src/cli/clipboard.js +11 -2
  57. package/dist/src/cli/detach.js +2 -2
  58. package/dist/src/cli/dryRun.js +29 -25
  59. package/dist/src/cli/duplicatePromptGuard.js +3 -3
  60. package/dist/src/cli/engine.js +9 -9
  61. package/dist/src/cli/errorUtils.js +1 -1
  62. package/dist/src/cli/fileSize.js +3 -3
  63. package/dist/src/cli/format.js +2 -2
  64. package/dist/src/cli/help.js +28 -28
  65. package/dist/src/cli/hiddenAliases.js +3 -3
  66. package/dist/src/cli/markdownBundle.js +7 -7
  67. package/dist/src/cli/markdownRenderer.js +15 -15
  68. package/dist/src/cli/notifier.js +77 -67
  69. package/dist/src/cli/options.js +127 -106
  70. package/dist/src/cli/oscUtils.js +1 -1
  71. package/dist/src/cli/promptRequirement.js +2 -2
  72. package/dist/src/cli/renderOutput.js +1 -1
  73. package/dist/src/cli/rootAlias.js +1 -1
  74. package/dist/src/cli/runOptions.js +32 -28
  75. package/dist/src/cli/sessionCommand.js +31 -21
  76. package/dist/src/cli/sessionDisplay.js +95 -81
  77. package/dist/src/cli/sessionLineage.js +6 -2
  78. package/dist/src/cli/sessionRunner.js +103 -93
  79. package/dist/src/cli/sessionTable.js +26 -23
  80. package/dist/src/cli/stdin.js +22 -0
  81. package/dist/src/cli/tagline.js +121 -124
  82. package/dist/src/cli/tui/index.js +139 -128
  83. package/dist/src/cli/writeOutputPath.js +5 -5
  84. package/dist/src/config.js +7 -7
  85. package/dist/src/gemini-web/browserSessionManager.js +19 -15
  86. package/dist/src/gemini-web/client.js +76 -70
  87. package/dist/src/gemini-web/executionMode.js +6 -8
  88. package/dist/src/gemini-web/executor.js +98 -93
  89. package/dist/src/gemini-web/index.js +1 -1
  90. package/dist/src/mcp/server.js +16 -12
  91. package/dist/src/mcp/tools/consult.js +51 -47
  92. package/dist/src/mcp/tools/sessionResources.js +12 -12
  93. package/dist/src/mcp/tools/sessions.js +26 -17
  94. package/dist/src/mcp/types.js +5 -5
  95. package/dist/src/mcp/utils.js +15 -7
  96. package/dist/src/oracle/background.js +15 -15
  97. package/dist/src/oracle/claude.js +53 -25
  98. package/dist/src/oracle/client.js +50 -41
  99. package/dist/src/oracle/config.js +96 -66
  100. package/dist/src/oracle/errors.js +38 -38
  101. package/dist/src/oracle/files.js +55 -46
  102. package/dist/src/oracle/finishLine.js +10 -8
  103. package/dist/src/oracle/format.js +3 -3
  104. package/dist/src/oracle/gemini.js +37 -33
  105. package/dist/src/oracle/logging.js +7 -7
  106. package/dist/src/oracle/markdown.js +28 -28
  107. package/dist/src/oracle/modelResolver.js +16 -16
  108. package/dist/src/oracle/multiModelRunner.js +12 -12
  109. package/dist/src/oracle/oscProgress.js +8 -8
  110. package/dist/src/oracle/promptAssembly.js +6 -3
  111. package/dist/src/oracle/request.js +16 -13
  112. package/dist/src/oracle/run.js +156 -134
  113. package/dist/src/oracle/runUtils.js +8 -5
  114. package/dist/src/oracle/tokenEstimate.js +6 -6
  115. package/dist/src/oracle/tokenStats.js +5 -5
  116. package/dist/src/oracle/tokenStringifier.js +5 -5
  117. package/dist/src/oracle.js +12 -12
  118. package/dist/src/oracleHome.js +3 -3
  119. package/dist/src/remote/client.js +25 -25
  120. package/dist/src/remote/health.js +20 -20
  121. package/dist/src/remote/remoteServiceConfig.js +9 -9
  122. package/dist/src/remote/server.js +129 -118
  123. package/dist/src/sessionManager.js +77 -75
  124. package/dist/src/sessionStore.js +3 -3
  125. package/dist/src/version.js +10 -10
  126. package/dist/vendor/oracle-notifier/README.md +2 -0
  127. package/package.json +66 -62
  128. package/vendor/oracle-notifier/README.md +2 -0
  129. package/dist/markdansi/types/index.js +0 -4
  130. package/dist/oracle/bin/oracle-cli.js +0 -472
  131. package/dist/oracle/src/browser/actions/assistantResponse.js +0 -471
  132. package/dist/oracle/src/browser/actions/attachments.js +0 -82
  133. package/dist/oracle/src/browser/actions/modelSelection.js +0 -190
  134. package/dist/oracle/src/browser/actions/navigation.js +0 -75
  135. package/dist/oracle/src/browser/actions/promptComposer.js +0 -167
  136. package/dist/oracle/src/browser/chromeLifecycle.js +0 -104
  137. package/dist/oracle/src/browser/config.js +0 -33
  138. package/dist/oracle/src/browser/constants.js +0 -40
  139. package/dist/oracle/src/browser/cookies.js +0 -210
  140. package/dist/oracle/src/browser/domDebug.js +0 -36
  141. package/dist/oracle/src/browser/index.js +0 -331
  142. package/dist/oracle/src/browser/pageActions.js +0 -5
  143. package/dist/oracle/src/browser/prompt.js +0 -88
  144. package/dist/oracle/src/browser/promptSummary.js +0 -20
  145. package/dist/oracle/src/browser/sessionRunner.js +0 -80
  146. package/dist/oracle/src/browser/types.js +0 -1
  147. package/dist/oracle/src/browser/utils.js +0 -62
  148. package/dist/oracle/src/browserMode.js +0 -1
  149. package/dist/oracle/src/cli/browserConfig.js +0 -44
  150. package/dist/oracle/src/cli/dryRun.js +0 -59
  151. package/dist/oracle/src/cli/engine.js +0 -17
  152. package/dist/oracle/src/cli/errorUtils.js +0 -9
  153. package/dist/oracle/src/cli/help.js +0 -70
  154. package/dist/oracle/src/cli/markdownRenderer.js +0 -15
  155. package/dist/oracle/src/cli/options.js +0 -103
  156. package/dist/oracle/src/cli/promptRequirement.js +0 -14
  157. package/dist/oracle/src/cli/rootAlias.js +0 -30
  158. package/dist/oracle/src/cli/sessionCommand.js +0 -77
  159. package/dist/oracle/src/cli/sessionDisplay.js +0 -270
  160. package/dist/oracle/src/cli/sessionRunner.js +0 -94
  161. package/dist/oracle/src/heartbeat.js +0 -43
  162. package/dist/oracle/src/oracle/client.js +0 -48
  163. package/dist/oracle/src/oracle/config.js +0 -29
  164. package/dist/oracle/src/oracle/errors.js +0 -101
  165. package/dist/oracle/src/oracle/files.js +0 -220
  166. package/dist/oracle/src/oracle/format.js +0 -33
  167. package/dist/oracle/src/oracle/fsAdapter.js +0 -7
  168. package/dist/oracle/src/oracle/oscProgress.js +0 -60
  169. package/dist/oracle/src/oracle/request.js +0 -48
  170. package/dist/oracle/src/oracle/run.js +0 -444
  171. package/dist/oracle/src/oracle/tokenStats.js +0 -39
  172. package/dist/oracle/src/oracle/types.js +0 -1
  173. package/dist/oracle/src/oracle.js +0 -9
  174. package/dist/oracle/src/sessionManager.js +0 -205
  175. package/dist/oracle/src/version.js +0 -39
  176. package/dist/scripts/chrome/browser-tools.js +0 -295
  177. package/dist/src/browser/profileSync.js +0 -141
@@ -1,39 +1,39 @@
1
- import { mkdir, readFile, writeFile } from 'node:fs/promises';
2
- import path from 'node:path';
3
- const USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36';
4
- const MODEL_HEADER_NAME = 'x-goog-ext-525001261-jspb';
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
4
+ const MODEL_HEADER_NAME = "x-goog-ext-525001261-jspb";
5
5
  const MODEL_HEADERS = {
6
- 'gemini-3-pro': '[1,null,null,null,"9d8ca3786ebdfbea",null,null,0,[4]]',
7
- 'gemini-3-pro-deep-think': '[1,null,null,null,"e6fa609c3fa255c0",null,null,0,[4],null,null,3]',
8
- 'gemini-2.5-pro': '[1,null,null,null,"4af6c7f5da75d65d",null,null,0,[4]]',
9
- 'gemini-2.5-flash': '[1,null,null,null,"9ec249fc9ad08861",null,null,0,[4]]',
6
+ "gemini-3-pro": '[1,null,null,null,"9d8ca3786ebdfbea",null,null,0,[4]]',
7
+ "gemini-3-pro-deep-think": '[1,null,null,null,"e6fa609c3fa255c0",null,null,0,[4],null,null,3]',
8
+ "gemini-2.5-pro": '[1,null,null,null,"4af6c7f5da75d65d",null,null,0,[4]]',
9
+ "gemini-2.5-flash": '[1,null,null,null,"9ec249fc9ad08861",null,null,0,[4]]',
10
10
  };
11
- const GEMINI_APP_URL = 'https://gemini.google.com/app';
12
- const GEMINI_STREAM_GENERATE_URL = 'https://gemini.google.com/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate';
13
- const GEMINI_UPLOAD_URL = 'https://content-push.googleapis.com/upload';
14
- const GEMINI_UPLOAD_PUSH_ID = 'feeds/mcudyrk2a4khkz';
11
+ const GEMINI_APP_URL = "https://gemini.google.com/app";
12
+ const GEMINI_STREAM_GENERATE_URL = "https://gemini.google.com/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate";
13
+ const GEMINI_UPLOAD_URL = "https://content-push.googleapis.com/upload";
14
+ const GEMINI_UPLOAD_PUSH_ID = "feeds/mcudyrk2a4khkz";
15
15
  const GEMINI_UPLOAD_MIME_TYPES = {
16
- '.bmp': 'image/bmp',
17
- '.gif': 'image/gif',
18
- '.jpeg': 'image/jpeg',
19
- '.jpg': 'image/jpeg',
20
- '.pdf': 'application/pdf',
21
- '.png': 'image/png',
22
- '.svg': 'image/svg+xml',
23
- '.webp': 'image/webp',
16
+ ".bmp": "image/bmp",
17
+ ".gif": "image/gif",
18
+ ".jpeg": "image/jpeg",
19
+ ".jpg": "image/jpeg",
20
+ ".pdf": "application/pdf",
21
+ ".png": "image/png",
22
+ ".svg": "image/svg+xml",
23
+ ".webp": "image/webp",
24
24
  };
25
25
  function getNestedValue(value, pathParts, fallback) {
26
26
  let current = value;
27
27
  for (const part of pathParts) {
28
28
  if (current == null)
29
29
  return fallback;
30
- if (typeof part === 'number') {
30
+ if (typeof part === "number") {
31
31
  if (!Array.isArray(current))
32
32
  return fallback;
33
33
  current = current[part];
34
34
  }
35
35
  else {
36
- if (typeof current !== 'object')
36
+ if (typeof current !== "object")
37
37
  return fallback;
38
38
  current = current[part];
39
39
  }
@@ -42,40 +42,40 @@ function getNestedValue(value, pathParts, fallback) {
42
42
  }
43
43
  function buildCookieHeader(cookieMap) {
44
44
  return Object.entries(cookieMap)
45
- .filter(([, value]) => typeof value === 'string' && value.length > 0)
45
+ .filter(([, value]) => typeof value === "string" && value.length > 0)
46
46
  .map(([name, value]) => `${name}=${value}`)
47
- .join('; ');
47
+ .join("; ");
48
48
  }
49
49
  export async function fetchGeminiAccessToken(cookieMap, signal) {
50
50
  const cookieHeader = buildCookieHeader(cookieMap);
51
51
  const res = await fetch(GEMINI_APP_URL, {
52
- redirect: 'follow',
52
+ redirect: "follow",
53
53
  signal,
54
54
  headers: {
55
55
  cookie: cookieHeader,
56
- 'user-agent': USER_AGENT,
56
+ "user-agent": USER_AGENT,
57
57
  },
58
58
  });
59
59
  const html = await res.text();
60
- const tokens = ['SNlM0e', 'thykhd'];
60
+ const tokens = ["SNlM0e", "thykhd"];
61
61
  for (const key of tokens) {
62
62
  const match = html.match(new RegExp(`"${key}":"(.*?)"`));
63
63
  if (match?.[1])
64
64
  return match[1];
65
65
  }
66
- throw new Error('Unable to locate Gemini access token on gemini.google.com/app (missing SNlM0e/thykhd).');
66
+ throw new Error("Unable to locate Gemini access token on gemini.google.com/app (missing SNlM0e/thykhd).");
67
67
  }
68
68
  function trimGeminiJsonEnvelope(text) {
69
- const start = text.indexOf('[');
70
- const end = text.lastIndexOf(']');
69
+ const start = text.indexOf("[");
70
+ const end = text.lastIndexOf("]");
71
71
  if (start === -1 || end === -1 || end <= start) {
72
- throw new Error('Gemini response did not contain a JSON payload.');
72
+ throw new Error("Gemini response did not contain a JSON payload.");
73
73
  }
74
74
  return text.slice(start, end + 1);
75
75
  }
76
76
  function extractErrorCode(responseJson) {
77
77
  const code = getNestedValue(responseJson, [0, 5, 2, 0, 1, 0], -1);
78
- return typeof code === 'number' && code >= 0 ? code : undefined;
78
+ return typeof code === "number" && code >= 0 ? code : undefined;
79
79
  }
80
80
  function extractGgdlUrls(rawText) {
81
81
  const matches = rawText.match(/https:\/\/lh3\.googleusercontent\.com\/gg-dl\/[^\s"']+/g) ?? [];
@@ -90,18 +90,18 @@ function extractGgdlUrls(rawText) {
90
90
  return urls;
91
91
  }
92
92
  function ensureFullSizeImageUrl(url) {
93
- if (url.includes('=s2048'))
93
+ if (url.includes("=s2048"))
94
94
  return url;
95
- if (url.includes('=s'))
95
+ if (url.includes("=s"))
96
96
  return url;
97
97
  return `${url}=s2048`;
98
98
  }
99
99
  async function fetchWithCookiePreservingRedirects(url, init, signal, maxRedirects = 10) {
100
100
  let current = url;
101
101
  for (let i = 0; i <= maxRedirects; i += 1) {
102
- const res = await fetch(current, { ...init, redirect: 'manual', signal });
102
+ const res = await fetch(current, { ...init, redirect: "manual", signal });
103
103
  if (res.status >= 300 && res.status < 400) {
104
- const location = res.headers.get('location');
104
+ const location = res.headers.get("location");
105
105
  if (!location)
106
106
  return res;
107
107
  current = new URL(location, current).toString();
@@ -116,7 +116,7 @@ async function downloadGeminiImage(url, cookieMap, outputPath, signal) {
116
116
  const res = await fetchWithCookiePreservingRedirects(ensureFullSizeImageUrl(url), {
117
117
  headers: {
118
118
  cookie: cookieHeader,
119
- 'user-agent': USER_AGENT,
119
+ "user-agent": USER_AGENT,
120
120
  },
121
121
  }, signal);
122
122
  if (!res.ok) {
@@ -130,16 +130,16 @@ async function uploadGeminiFile(filePath, signal) {
130
130
  const absPath = path.resolve(process.cwd(), filePath);
131
131
  const data = await readFile(absPath);
132
132
  const fileName = path.basename(absPath);
133
- const mimeType = GEMINI_UPLOAD_MIME_TYPES[path.extname(absPath).toLowerCase()] ?? 'application/octet-stream';
133
+ const mimeType = GEMINI_UPLOAD_MIME_TYPES[path.extname(absPath).toLowerCase()] ?? "application/octet-stream";
134
134
  const form = new FormData();
135
- form.append('file', new Blob([data], { type: mimeType }), fileName);
135
+ form.append("file", new Blob([data], { type: mimeType }), fileName);
136
136
  const res = await fetch(GEMINI_UPLOAD_URL, {
137
- method: 'POST',
138
- redirect: 'follow',
137
+ method: "POST",
138
+ redirect: "follow",
139
139
  signal,
140
140
  headers: {
141
- 'push-id': GEMINI_UPLOAD_PUSH_ID,
142
- 'user-agent': USER_AGENT,
141
+ "push-id": GEMINI_UPLOAD_PUSH_ID,
142
+ "user-agent": USER_AGENT,
143
143
  },
144
144
  body: form,
145
145
  });
@@ -176,9 +176,15 @@ export function parseGeminiStreamGenerateResponse(rawText) {
176
176
  const parsed = JSON.parse(partBody);
177
177
  const candidateList = getNestedValue(parsed, [4], []);
178
178
  if (Array.isArray(candidateList) && candidateList.length > 0) {
179
- bodyIndex = i;
180
- body = parsed;
181
- break;
179
+ const candidateText = getNestedValue(candidateList[0], [1, 0], "");
180
+ const hasText = typeof candidateText === "string" && candidateText.length > 0;
181
+ if (body === null) {
182
+ bodyIndex = i;
183
+ body = parsed;
184
+ }
185
+ else if (hasText) {
186
+ body = parsed;
187
+ }
182
188
  }
183
189
  }
184
190
  catch {
@@ -187,7 +193,7 @@ export function parseGeminiStreamGenerateResponse(rawText) {
187
193
  }
188
194
  const candidateList = getNestedValue(body, [4], []);
189
195
  const firstCandidate = candidateList[0];
190
- const textRaw = getNestedValue(firstCandidate, [1, 0], '');
196
+ const textRaw = getNestedValue(firstCandidate, [1, 0], "");
191
197
  const cardContent = /^http:\/\/googleusercontent\.com\/card_content\/\d+/.test(textRaw);
192
198
  const text = cardContent
193
199
  ? (getNestedValue(firstCandidate, [22, 0], null) ?? textRaw)
@@ -201,7 +207,7 @@ export function parseGeminiStreamGenerateResponse(rawText) {
201
207
  if (!url)
202
208
  continue;
203
209
  images.push({
204
- kind: 'web',
210
+ kind: "web",
205
211
  url,
206
212
  title: getNestedValue(webImage, [7, 0], undefined),
207
213
  alt: getNestedValue(webImage, [0, 4], undefined),
@@ -233,10 +239,10 @@ export function parseGeminiStreamGenerateResponse(rawText) {
233
239
  if (!url)
234
240
  continue;
235
241
  images.push({
236
- kind: 'generated',
242
+ kind: "generated",
237
243
  url,
238
- title: '[Generated Image]',
239
- alt: '',
244
+ title: "[Generated Image]",
245
+ alt: "",
240
246
  });
241
247
  }
242
248
  }
@@ -251,24 +257,24 @@ export async function runGeminiWebOnce(input) {
251
257
  const uploaded = [];
252
258
  for (const file of input.files ?? []) {
253
259
  if (input.signal?.aborted) {
254
- throw new Error('Gemini web run aborted before upload.');
260
+ throw new Error("Gemini web run aborted before upload.");
255
261
  }
256
262
  uploaded.push(await uploadGeminiFile(file, input.signal));
257
263
  }
258
264
  const fReq = buildGeminiFReqPayload(input.prompt, uploaded, input.chatMetadata ?? null);
259
265
  const params = new URLSearchParams();
260
- params.set('at', at);
261
- params.set('f.req', fReq);
266
+ params.set("at", at);
267
+ params.set("f.req", fReq);
262
268
  const res = await fetch(GEMINI_STREAM_GENERATE_URL, {
263
- method: 'POST',
264
- redirect: 'follow',
269
+ method: "POST",
270
+ redirect: "follow",
265
271
  signal: input.signal,
266
272
  headers: {
267
- 'content-type': 'application/x-www-form-urlencoded;charset=utf-8',
268
- origin: 'https://gemini.google.com',
269
- referer: 'https://gemini.google.com/',
270
- 'x-same-domain': '1',
271
- 'user-agent': USER_AGENT,
273
+ "content-type": "application/x-www-form-urlencoded;charset=utf-8",
274
+ origin: "https://gemini.google.com",
275
+ referer: "https://gemini.google.com/",
276
+ "x-same-domain": "1",
277
+ "user-agent": USER_AGENT,
272
278
  cookie: cookieHeader,
273
279
  [MODEL_HEADER_NAME]: MODEL_HEADERS[input.model],
274
280
  },
@@ -278,7 +284,7 @@ export async function runGeminiWebOnce(input) {
278
284
  if (!res.ok) {
279
285
  return {
280
286
  rawResponseText,
281
- text: '',
287
+ text: "",
282
288
  thoughts: null,
283
289
  metadata: input.chatMetadata ?? null,
284
290
  images: [],
@@ -289,7 +295,7 @@ export async function runGeminiWebOnce(input) {
289
295
  const parsed = parseGeminiStreamGenerateResponse(rawResponseText);
290
296
  return {
291
297
  rawResponseText,
292
- text: parsed.text ?? '',
298
+ text: parsed.text ?? "",
293
299
  thoughts: parsed.thoughts,
294
300
  metadata: parsed.metadata,
295
301
  images: parsed.images,
@@ -307,25 +313,25 @@ export async function runGeminiWebOnce(input) {
307
313
  const errorCode = extractErrorCode(responseJson);
308
314
  return {
309
315
  rawResponseText,
310
- text: '',
316
+ text: "",
311
317
  thoughts: null,
312
318
  metadata: input.chatMetadata ?? null,
313
319
  images: [],
314
- errorCode: typeof errorCode === 'number' ? errorCode : undefined,
315
- errorMessage: error instanceof Error ? error.message : String(error ?? ''),
320
+ errorCode: typeof errorCode === "number" ? errorCode : undefined,
321
+ errorMessage: error instanceof Error ? error.message : String(error ?? ""),
316
322
  };
317
323
  }
318
324
  }
319
325
  export async function runGeminiWebWithFallback(input) {
320
326
  const attempt = await runGeminiWebOnce(input);
321
- if (isGeminiModelUnavailable(attempt.errorCode) && input.model !== 'gemini-2.5-flash') {
322
- const fallback = await runGeminiWebOnce({ ...input, model: 'gemini-2.5-flash' });
323
- return { ...fallback, effectiveModel: 'gemini-2.5-flash' };
327
+ if (isGeminiModelUnavailable(attempt.errorCode) && input.model !== "gemini-2.5-flash") {
328
+ const fallback = await runGeminiWebOnce({ ...input, model: "gemini-2.5-flash" });
329
+ return { ...fallback, effectiveModel: "gemini-2.5-flash" };
324
330
  }
325
331
  return { ...attempt, effectiveModel: input.model };
326
332
  }
327
333
  export async function saveFirstGeminiImageFromOutput(output, cookieMap, outputPath, signal) {
328
- const generatedOrWeb = output.images.find((img) => img.kind === 'generated') ?? output.images[0];
334
+ const generatedOrWeb = output.images.find((img) => img.kind === "generated") ?? output.images[0];
329
335
  if (generatedOrWeb?.url) {
330
336
  await downloadGeminiImage(generatedOrWeb.url, cookieMap, outputPath, signal);
331
337
  return { saved: true, imageCount: output.images.length };
@@ -1,18 +1,16 @@
1
1
  export function selectGeminiExecutionMode(input) {
2
2
  const reasons = [];
3
- if (input.model !== 'gemini-3-pro-deep-think') {
4
- return { mode: 'http', reasons: ['model'] };
3
+ if (input.model !== "gemini-3-pro-deep-think") {
4
+ return { mode: "http", reasons: ["model"] };
5
5
  }
6
6
  if (input.attachmentPaths.length > 0) {
7
- reasons.push('attachments');
7
+ reasons.push("attachments");
8
8
  }
9
9
  if (input.generateImagePath) {
10
- reasons.push('image-generation');
10
+ reasons.push("image-generation");
11
11
  }
12
12
  if (input.editImagePath) {
13
- reasons.push('image-edit');
13
+ reasons.push("image-edit");
14
14
  }
15
- return reasons.length === 0
16
- ? { mode: 'dom', reasons: [] }
17
- : { mode: 'http', reasons };
15
+ return reasons.length === 0 ? { mode: "dom", reasons: [] } : { mode: "http", reasons };
18
16
  }