oh-my-opencode 1.2.3 → 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.
- package/dist/google-auth.js +151 -49
- package/dist/index.js +6893 -3888
- package/package.json +1 -1
- package/dist/agents/look-at.d.ts +0 -2
- package/dist/hooks/ultrawork-mode/constants.d.ts +0 -15
- package/dist/hooks/ultrawork-mode/detector.d.ts +0 -16
- package/dist/hooks/ultrawork-mode/index.d.ts +0 -40
- package/dist/hooks/ultrawork-mode/types.d.ts +0 -20
package/dist/google-auth.js
CHANGED
|
@@ -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
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
debugLog3(`
|
|
1190
|
-
|
|
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
|
|
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
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
endpoint
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
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
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
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
|