oh-my-opencode 1.2.2 → 1.2.4

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.
@@ -91,7 +91,7 @@ export declare const AgentOverrideConfigSchema: z.ZodObject<{
91
91
  }, z.core.$strip>>;
92
92
  }, z.core.$strip>;
93
93
  export declare const AgentOverridesSchema: z.ZodObject<{
94
- build: z.ZodOptional<z.ZodOptional<z.ZodObject<{
94
+ build: z.ZodOptional<z.ZodObject<{
95
95
  model: z.ZodOptional<z.ZodString>;
96
96
  temperature: z.ZodOptional<z.ZodNumber>;
97
97
  top_p: z.ZodOptional<z.ZodNumber>;
@@ -136,8 +136,8 @@ export declare const AgentOverridesSchema: z.ZodObject<{
136
136
  ask: "ask";
137
137
  }>>;
138
138
  }, z.core.$strip>>;
139
- }, z.core.$strip>>>;
140
- oracle: z.ZodOptional<z.ZodOptional<z.ZodObject<{
139
+ }, z.core.$strip>>;
140
+ oracle: z.ZodOptional<z.ZodObject<{
141
141
  model: z.ZodOptional<z.ZodString>;
142
142
  temperature: z.ZodOptional<z.ZodNumber>;
143
143
  top_p: z.ZodOptional<z.ZodNumber>;
@@ -182,8 +182,8 @@ export declare const AgentOverridesSchema: z.ZodObject<{
182
182
  ask: "ask";
183
183
  }>>;
184
184
  }, z.core.$strip>>;
185
- }, z.core.$strip>>>;
186
- librarian: z.ZodOptional<z.ZodOptional<z.ZodObject<{
185
+ }, z.core.$strip>>;
186
+ librarian: z.ZodOptional<z.ZodObject<{
187
187
  model: z.ZodOptional<z.ZodString>;
188
188
  temperature: z.ZodOptional<z.ZodNumber>;
189
189
  top_p: z.ZodOptional<z.ZodNumber>;
@@ -228,8 +228,8 @@ export declare const AgentOverridesSchema: z.ZodObject<{
228
228
  ask: "ask";
229
229
  }>>;
230
230
  }, z.core.$strip>>;
231
- }, z.core.$strip>>>;
232
- explore: z.ZodOptional<z.ZodOptional<z.ZodObject<{
231
+ }, z.core.$strip>>;
232
+ explore: z.ZodOptional<z.ZodObject<{
233
233
  model: z.ZodOptional<z.ZodString>;
234
234
  temperature: z.ZodOptional<z.ZodNumber>;
235
235
  top_p: z.ZodOptional<z.ZodNumber>;
@@ -274,8 +274,8 @@ export declare const AgentOverridesSchema: z.ZodObject<{
274
274
  ask: "ask";
275
275
  }>>;
276
276
  }, z.core.$strip>>;
277
- }, z.core.$strip>>>;
278
- "frontend-ui-ux-engineer": z.ZodOptional<z.ZodOptional<z.ZodObject<{
277
+ }, z.core.$strip>>;
278
+ "frontend-ui-ux-engineer": z.ZodOptional<z.ZodObject<{
279
279
  model: z.ZodOptional<z.ZodString>;
280
280
  temperature: z.ZodOptional<z.ZodNumber>;
281
281
  top_p: z.ZodOptional<z.ZodNumber>;
@@ -320,8 +320,8 @@ export declare const AgentOverridesSchema: z.ZodObject<{
320
320
  ask: "ask";
321
321
  }>>;
322
322
  }, z.core.$strip>>;
323
- }, z.core.$strip>>>;
324
- "document-writer": z.ZodOptional<z.ZodOptional<z.ZodObject<{
323
+ }, z.core.$strip>>;
324
+ "document-writer": z.ZodOptional<z.ZodObject<{
325
325
  model: z.ZodOptional<z.ZodString>;
326
326
  temperature: z.ZodOptional<z.ZodNumber>;
327
327
  top_p: z.ZodOptional<z.ZodNumber>;
@@ -366,8 +366,8 @@ export declare const AgentOverridesSchema: z.ZodObject<{
366
366
  ask: "ask";
367
367
  }>>;
368
368
  }, z.core.$strip>>;
369
- }, z.core.$strip>>>;
370
- "multimodal-looker": z.ZodOptional<z.ZodOptional<z.ZodObject<{
369
+ }, z.core.$strip>>;
370
+ "multimodal-looker": z.ZodOptional<z.ZodObject<{
371
371
  model: z.ZodOptional<z.ZodString>;
372
372
  temperature: z.ZodOptional<z.ZodNumber>;
373
373
  top_p: z.ZodOptional<z.ZodNumber>;
@@ -412,7 +412,7 @@ export declare const AgentOverridesSchema: z.ZodObject<{
412
412
  ask: "ask";
413
413
  }>>;
414
414
  }, z.core.$strip>>;
415
- }, z.core.$strip>>>;
415
+ }, z.core.$strip>>;
416
416
  }, z.core.$strip>;
417
417
  export declare const ClaudeCodeConfigSchema: z.ZodObject<{
418
418
  mcp: z.ZodOptional<z.ZodBoolean>;
@@ -460,7 +460,7 @@ export declare const OhMyOpenCodeConfigSchema: z.ZodObject<{
460
460
  "keyword-detector": "keyword-detector";
461
461
  }>>>;
462
462
  agents: z.ZodOptional<z.ZodObject<{
463
- build: z.ZodOptional<z.ZodOptional<z.ZodObject<{
463
+ build: z.ZodOptional<z.ZodObject<{
464
464
  model: z.ZodOptional<z.ZodString>;
465
465
  temperature: z.ZodOptional<z.ZodNumber>;
466
466
  top_p: z.ZodOptional<z.ZodNumber>;
@@ -505,8 +505,8 @@ export declare const OhMyOpenCodeConfigSchema: z.ZodObject<{
505
505
  ask: "ask";
506
506
  }>>;
507
507
  }, z.core.$strip>>;
508
- }, z.core.$strip>>>;
509
- oracle: z.ZodOptional<z.ZodOptional<z.ZodObject<{
508
+ }, z.core.$strip>>;
509
+ oracle: z.ZodOptional<z.ZodObject<{
510
510
  model: z.ZodOptional<z.ZodString>;
511
511
  temperature: z.ZodOptional<z.ZodNumber>;
512
512
  top_p: z.ZodOptional<z.ZodNumber>;
@@ -551,8 +551,8 @@ export declare const OhMyOpenCodeConfigSchema: z.ZodObject<{
551
551
  ask: "ask";
552
552
  }>>;
553
553
  }, z.core.$strip>>;
554
- }, z.core.$strip>>>;
555
- librarian: z.ZodOptional<z.ZodOptional<z.ZodObject<{
554
+ }, z.core.$strip>>;
555
+ librarian: z.ZodOptional<z.ZodObject<{
556
556
  model: z.ZodOptional<z.ZodString>;
557
557
  temperature: z.ZodOptional<z.ZodNumber>;
558
558
  top_p: z.ZodOptional<z.ZodNumber>;
@@ -597,8 +597,8 @@ export declare const OhMyOpenCodeConfigSchema: z.ZodObject<{
597
597
  ask: "ask";
598
598
  }>>;
599
599
  }, z.core.$strip>>;
600
- }, z.core.$strip>>>;
601
- explore: z.ZodOptional<z.ZodOptional<z.ZodObject<{
600
+ }, z.core.$strip>>;
601
+ explore: z.ZodOptional<z.ZodObject<{
602
602
  model: z.ZodOptional<z.ZodString>;
603
603
  temperature: z.ZodOptional<z.ZodNumber>;
604
604
  top_p: z.ZodOptional<z.ZodNumber>;
@@ -643,8 +643,8 @@ export declare const OhMyOpenCodeConfigSchema: z.ZodObject<{
643
643
  ask: "ask";
644
644
  }>>;
645
645
  }, z.core.$strip>>;
646
- }, z.core.$strip>>>;
647
- "frontend-ui-ux-engineer": z.ZodOptional<z.ZodOptional<z.ZodObject<{
646
+ }, z.core.$strip>>;
647
+ "frontend-ui-ux-engineer": z.ZodOptional<z.ZodObject<{
648
648
  model: z.ZodOptional<z.ZodString>;
649
649
  temperature: z.ZodOptional<z.ZodNumber>;
650
650
  top_p: z.ZodOptional<z.ZodNumber>;
@@ -689,8 +689,8 @@ export declare const OhMyOpenCodeConfigSchema: z.ZodObject<{
689
689
  ask: "ask";
690
690
  }>>;
691
691
  }, z.core.$strip>>;
692
- }, z.core.$strip>>>;
693
- "document-writer": z.ZodOptional<z.ZodOptional<z.ZodObject<{
692
+ }, z.core.$strip>>;
693
+ "document-writer": z.ZodOptional<z.ZodObject<{
694
694
  model: z.ZodOptional<z.ZodString>;
695
695
  temperature: z.ZodOptional<z.ZodNumber>;
696
696
  top_p: z.ZodOptional<z.ZodNumber>;
@@ -735,8 +735,8 @@ export declare const OhMyOpenCodeConfigSchema: z.ZodObject<{
735
735
  ask: "ask";
736
736
  }>>;
737
737
  }, z.core.$strip>>;
738
- }, z.core.$strip>>>;
739
- "multimodal-looker": z.ZodOptional<z.ZodOptional<z.ZodObject<{
738
+ }, z.core.$strip>>;
739
+ "multimodal-looker": z.ZodOptional<z.ZodObject<{
740
740
  model: z.ZodOptional<z.ZodString>;
741
741
  temperature: z.ZodOptional<z.ZodNumber>;
742
742
  top_p: z.ZodOptional<z.ZodNumber>;
@@ -781,7 +781,7 @@ export declare const OhMyOpenCodeConfigSchema: z.ZodObject<{
781
781
  ask: "ask";
782
782
  }>>;
783
783
  }, z.core.$strip>>;
784
- }, z.core.$strip>>>;
784
+ }, z.core.$strip>>;
785
785
  }, z.core.$strip>>;
786
786
  claude_code: z.ZodOptional<z.ZodObject<{
787
787
  mcp: z.ZodOptional<z.ZodBoolean>;
@@ -1130,6 +1130,32 @@ function isRetryableError(status) {
1130
1130
  return true;
1131
1131
  return false;
1132
1132
  }
1133
+ var GCP_PERMISSION_ERROR_PATTERNS = [
1134
+ "PERMISSION_DENIED",
1135
+ "does not have permission",
1136
+ "Cloud AI Companion API has not been used",
1137
+ "has not been enabled"
1138
+ ];
1139
+ function isGcpPermissionError(text) {
1140
+ return GCP_PERMISSION_ERROR_PATTERNS.some((pattern) => text.includes(pattern));
1141
+ }
1142
+ function calculateRetryDelay(attempt) {
1143
+ return Math.min(200 * Math.pow(2, attempt), 2000);
1144
+ }
1145
+ async function isRetryableResponse(response) {
1146
+ if (isRetryableError(response.status))
1147
+ return true;
1148
+ if (response.status === 403) {
1149
+ try {
1150
+ const text = await response.clone().text();
1151
+ if (text.includes("SUBSCRIPTION_REQUIRED") || text.includes("Gemini Code Assist license")) {
1152
+ debugLog3(`[RETRY] 403 SUBSCRIPTION_REQUIRED detected, will retry with next endpoint`);
1153
+ return true;
1154
+ }
1155
+ } catch {}
1156
+ }
1157
+ return false;
1158
+ }
1133
1159
  async function attemptFetch(options) {
1134
1160
  const { endpoint, url, init, accessToken, projectId, sessionId, modelName, thoughtSignature } = options;
1135
1161
  debugLog3(`Trying endpoint: ${endpoint}`);
@@ -1178,18 +1204,40 @@ async function attemptFetch(options) {
1178
1204
  thoughtSignature
1179
1205
  });
1180
1206
  debugLog3(`[REQ] streaming=${transformed.streaming}, url=${transformed.url}`);
1181
- const response = await fetch(transformed.url, {
1182
- method: init.method || "POST",
1183
- headers: transformed.headers,
1184
- body: JSON.stringify(transformed.body),
1185
- signal: init.signal
1186
- });
1187
- debugLog3(`[RESP] status=${response.status} content-type=${response.headers.get("content-type") ?? ""} url=${response.url}`);
1188
- if (!response.ok && isRetryableError(response.status)) {
1189
- debugLog3(`Endpoint failed: ${endpoint} (status: ${response.status}), trying next`);
1190
- return null;
1207
+ const maxPermissionRetries = 10;
1208
+ for (let attempt = 0;attempt <= maxPermissionRetries; attempt++) {
1209
+ const response = await fetch(transformed.url, {
1210
+ method: init.method || "POST",
1211
+ headers: transformed.headers,
1212
+ body: JSON.stringify(transformed.body),
1213
+ signal: init.signal
1214
+ });
1215
+ debugLog3(`[RESP] status=${response.status} content-type=${response.headers.get("content-type") ?? ""} url=${response.url}`);
1216
+ if (response.status === 401) {
1217
+ debugLog3(`[401] Unauthorized response detected, signaling token refresh needed`);
1218
+ return "needs-refresh";
1219
+ }
1220
+ if (response.status === 403) {
1221
+ try {
1222
+ const text = await response.clone().text();
1223
+ if (isGcpPermissionError(text)) {
1224
+ if (attempt < maxPermissionRetries) {
1225
+ const delay = calculateRetryDelay(attempt);
1226
+ debugLog3(`[RETRY] GCP permission error, retry ${attempt + 1}/${maxPermissionRetries} after ${delay}ms`);
1227
+ await new Promise((resolve) => setTimeout(resolve, delay));
1228
+ continue;
1229
+ }
1230
+ debugLog3(`[RETRY] GCP permission error, max retries exceeded`);
1231
+ }
1232
+ } catch {}
1233
+ }
1234
+ if (!response.ok && await isRetryableResponse(response)) {
1235
+ debugLog3(`Endpoint failed: ${endpoint} (status: ${response.status}), trying next`);
1236
+ return null;
1237
+ }
1238
+ return response;
1191
1239
  }
1192
- return response;
1240
+ return null;
1193
1241
  } catch (error) {
1194
1242
  debugLog3(`Endpoint failed: ${endpoint} (${error instanceof Error ? error.message : "Unknown error"}), trying next`);
1195
1243
  return null;
@@ -1318,45 +1366,99 @@ function createAntigravityFetch(getAuth, client, providerId, clientId, clientSec
1318
1366
  const sessionId = getOrCreateSessionId(fetchInstanceId);
1319
1367
  const thoughtSignature = getThoughtSignature(fetchInstanceId);
1320
1368
  debugLog3(`[TSIG][GET] sessionId=${sessionId}, signature=${thoughtSignature ? thoughtSignature.substring(0, 20) + "..." : "none"}`);
1321
- for (let i = 0;i < maxEndpoints; i++) {
1322
- const endpoint = ANTIGRAVITY_ENDPOINT_FALLBACKS[i];
1323
- const response = await attemptFetch({
1324
- endpoint,
1325
- url,
1326
- init,
1327
- accessToken: cachedTokens.access_token,
1328
- projectId,
1329
- sessionId,
1330
- modelName,
1331
- thoughtSignature
1332
- });
1333
- if (response === "pass-through") {
1334
- debugLog3("Non-string body detected, passing through with auth headers");
1335
- const headersWithAuth = {
1336
- ...init.headers,
1337
- Authorization: `Bearer ${cachedTokens.access_token}`
1338
- };
1339
- return fetch(url, { ...init, headers: headersWithAuth });
1340
- }
1341
- if (response) {
1342
- debugLog3(`Success with endpoint: ${endpoint}`);
1343
- const transformedResponse = await transformResponseWithThinking(response, modelName || "", fetchInstanceId);
1344
- return transformedResponse;
1345
- }
1346
- }
1347
- const errorMessage = `All Antigravity endpoints failed after ${maxEndpoints} attempts`;
1348
- debugLog3(errorMessage);
1349
- return new Response(JSON.stringify({
1350
- error: {
1351
- message: errorMessage,
1352
- type: "endpoint_failure",
1353
- code: "all_endpoints_failed"
1369
+ let hasRefreshedFor401 = false;
1370
+ const executeWithEndpoints = async () => {
1371
+ for (let i = 0;i < maxEndpoints; i++) {
1372
+ const endpoint = ANTIGRAVITY_ENDPOINT_FALLBACKS[i];
1373
+ const response = await attemptFetch({
1374
+ endpoint,
1375
+ url,
1376
+ init,
1377
+ accessToken: cachedTokens.access_token,
1378
+ projectId,
1379
+ sessionId,
1380
+ modelName,
1381
+ thoughtSignature
1382
+ });
1383
+ if (response === "pass-through") {
1384
+ debugLog3("Non-string body detected, passing through with auth headers");
1385
+ const headersWithAuth = {
1386
+ ...init.headers,
1387
+ Authorization: `Bearer ${cachedTokens.access_token}`
1388
+ };
1389
+ return fetch(url, { ...init, headers: headersWithAuth });
1390
+ }
1391
+ if (response === "needs-refresh") {
1392
+ if (hasRefreshedFor401) {
1393
+ debugLog3("[401] Already refreshed once, returning unauthorized error");
1394
+ return new Response(JSON.stringify({
1395
+ error: {
1396
+ message: "Authentication failed after token refresh",
1397
+ type: "unauthorized",
1398
+ code: "token_refresh_failed"
1399
+ }
1400
+ }), {
1401
+ status: 401,
1402
+ statusText: "Unauthorized",
1403
+ headers: { "Content-Type": "application/json" }
1404
+ });
1405
+ }
1406
+ debugLog3("[401] Refreshing token and retrying...");
1407
+ hasRefreshedFor401 = true;
1408
+ try {
1409
+ const newTokens = await refreshAccessToken(refreshParts.refreshToken, clientId, clientSecret);
1410
+ cachedTokens = {
1411
+ type: "antigravity",
1412
+ access_token: newTokens.access_token,
1413
+ refresh_token: newTokens.refresh_token,
1414
+ expires_in: newTokens.expires_in,
1415
+ timestamp: Date.now()
1416
+ };
1417
+ clearProjectContextCache();
1418
+ const formattedRefresh = formatTokenForStorage(newTokens.refresh_token, refreshParts.projectId || "", refreshParts.managedProjectId);
1419
+ await client.set(providerId, {
1420
+ access: newTokens.access_token,
1421
+ refresh: formattedRefresh,
1422
+ expires: Date.now() + newTokens.expires_in * 1000
1423
+ });
1424
+ debugLog3("[401] Token refreshed, retrying request...");
1425
+ return executeWithEndpoints();
1426
+ } catch (refreshError) {
1427
+ debugLog3(`[401] Token refresh failed: ${refreshError instanceof Error ? refreshError.message : "Unknown error"}`);
1428
+ return new Response(JSON.stringify({
1429
+ error: {
1430
+ message: `Token refresh failed: ${refreshError instanceof Error ? refreshError.message : "Unknown error"}`,
1431
+ type: "unauthorized",
1432
+ code: "token_refresh_failed"
1433
+ }
1434
+ }), {
1435
+ status: 401,
1436
+ statusText: "Unauthorized",
1437
+ headers: { "Content-Type": "application/json" }
1438
+ });
1439
+ }
1440
+ }
1441
+ if (response) {
1442
+ debugLog3(`Success with endpoint: ${endpoint}`);
1443
+ const transformedResponse = await transformResponseWithThinking(response, modelName || "", fetchInstanceId);
1444
+ return transformedResponse;
1445
+ }
1354
1446
  }
1355
- }), {
1356
- status: 503,
1357
- statusText: "Service Unavailable",
1358
- headers: { "Content-Type": "application/json" }
1359
- });
1447
+ const errorMessage = `All Antigravity endpoints failed after ${maxEndpoints} attempts`;
1448
+ debugLog3(errorMessage);
1449
+ return new Response(JSON.stringify({
1450
+ error: {
1451
+ message: errorMessage,
1452
+ type: "endpoint_failure",
1453
+ code: "all_endpoints_failed"
1454
+ }
1455
+ }), {
1456
+ status: 503,
1457
+ statusText: "Service Unavailable",
1458
+ headers: { "Content-Type": "application/json" }
1459
+ });
1460
+ };
1461
+ return executeWithEndpoints();
1360
1462
  };
1361
1463
  }
1362
1464
  // src/auth/antigravity/plugin.ts