nolo-cli 0.1.53 → 0.1.54
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/index.js +1032 -495
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -9229,6 +9229,377 @@ var init_agentRecordHelpers = __esm({
|
|
|
9229
9229
|
}
|
|
9230
9230
|
});
|
|
9231
9231
|
|
|
9232
|
+
// packages/agent-runtime/antigravityOAuth.ts
|
|
9233
|
+
function getAntigravityUserAgent() {
|
|
9234
|
+
const version = process.env.NOLO_ANTIGRAVITY_VERSION || "2.1.4";
|
|
9235
|
+
const os2 = process.platform === "win32" ? "windows" : process.platform;
|
|
9236
|
+
const arch3 = process.arch === "x64" ? "amd64" : process.arch === "ia32" ? "386" : process.arch;
|
|
9237
|
+
return `antigravity/hub/${version} ${os2}/${arch3}`;
|
|
9238
|
+
}
|
|
9239
|
+
function resolveAntigravityCloudCodeBaseUrl(customProviderUrl) {
|
|
9240
|
+
const raw = (customProviderUrl ?? "").trim();
|
|
9241
|
+
if (!raw) return ANTIGRAVITY_CLOUD_CODE_BASE_URL;
|
|
9242
|
+
const trimmed = trimTrailingSlash(raw);
|
|
9243
|
+
if (trimmed.includes(ANTIGRAVITY_CLOUD_CODE_HOST)) {
|
|
9244
|
+
const base = trimmed.replace(/\/v1internal:.*$/i, "").replace(/\/$/, "");
|
|
9245
|
+
if (ANTIGRAVITY_LEGACY_GENERIC_BASE_RE.test(base)) {
|
|
9246
|
+
return ANTIGRAVITY_CLOUD_CODE_BASE_URL;
|
|
9247
|
+
}
|
|
9248
|
+
return base;
|
|
9249
|
+
}
|
|
9250
|
+
return ANTIGRAVITY_CLOUD_CODE_BASE_URL;
|
|
9251
|
+
}
|
|
9252
|
+
function isAntigravityOAuthAgent(agentConfig) {
|
|
9253
|
+
if (!agentConfig) return false;
|
|
9254
|
+
const apiKeyRef = (agentConfig.apiKeyRef ?? "").trim().toLowerCase();
|
|
9255
|
+
const provider = String(agentConfig.provider ?? "").trim().toLowerCase();
|
|
9256
|
+
const url = (agentConfig.customProviderUrl ?? "").trim().toLowerCase();
|
|
9257
|
+
return apiKeyRef === "antigravity" || provider === "google-antigravity" || url.includes(ANTIGRAVITY_CLOUD_CODE_HOST);
|
|
9258
|
+
}
|
|
9259
|
+
function readAntigravityProjectId(metadata) {
|
|
9260
|
+
const value = metadata?.projectId;
|
|
9261
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
9262
|
+
}
|
|
9263
|
+
var ANTIGRAVITY_CLOUD_CODE_BASE_URL, ANTIGRAVITY_CLOUD_CODE_HOST, ANTIGRAVITY_LEGACY_GENERIC_BASE_RE;
|
|
9264
|
+
var init_antigravityOAuth = __esm({
|
|
9265
|
+
"packages/agent-runtime/antigravityOAuth.ts"() {
|
|
9266
|
+
"use strict";
|
|
9267
|
+
init_providerResolution();
|
|
9268
|
+
ANTIGRAVITY_CLOUD_CODE_BASE_URL = "https://daily-cloudcode-pa.googleapis.com";
|
|
9269
|
+
ANTIGRAVITY_CLOUD_CODE_HOST = "cloudcode-pa.googleapis.com";
|
|
9270
|
+
ANTIGRAVITY_LEGACY_GENERIC_BASE_RE = /^https?:\/\/cloudcode-pa\.googleapis\.com$/i;
|
|
9271
|
+
}
|
|
9272
|
+
});
|
|
9273
|
+
|
|
9274
|
+
// packages/agent-runtime/antigravityWireModel.ts
|
|
9275
|
+
function resolveAntigravityWireModel(logicalModelId) {
|
|
9276
|
+
const id = logicalModelId.trim();
|
|
9277
|
+
const lower = id.toLowerCase();
|
|
9278
|
+
if (lower === "gemini-3.1-pro" || lower === "gemini-3.1-pro-preview") {
|
|
9279
|
+
const wireModelId = "gemini-3.1-pro-low";
|
|
9280
|
+
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
9281
|
+
}
|
|
9282
|
+
if (WIRE_PROFILES[id]) {
|
|
9283
|
+
return { wireModelId: id, profile: WIRE_PROFILES[id] };
|
|
9284
|
+
}
|
|
9285
|
+
return { wireModelId: id };
|
|
9286
|
+
}
|
|
9287
|
+
var WIRE_PROFILES;
|
|
9288
|
+
var init_antigravityWireModel = __esm({
|
|
9289
|
+
"packages/agent-runtime/antigravityWireModel.ts"() {
|
|
9290
|
+
"use strict";
|
|
9291
|
+
WIRE_PROFILES = {
|
|
9292
|
+
"gemini-3.5-flash-extra-low": { modelEnum: "MODEL_PLACEHOLDER_M187", maxOutputTokens: 65536 },
|
|
9293
|
+
"gemini-3.5-flash-low": { modelEnum: "MODEL_PLACEHOLDER_M20", maxOutputTokens: 65536 },
|
|
9294
|
+
"gemini-3-flash-agent": { modelEnum: "MODEL_PLACEHOLDER_M132", maxOutputTokens: 65536 },
|
|
9295
|
+
"gemini-3.1-pro-low": { modelEnum: "MODEL_PLACEHOLDER_M36", maxOutputTokens: 65535 },
|
|
9296
|
+
"gemini-pro-agent": { modelEnum: "MODEL_PLACEHOLDER_M16", maxOutputTokens: 65535 },
|
|
9297
|
+
"claude-sonnet-4-6": { maxOutputTokens: 64e3 },
|
|
9298
|
+
"claude-opus-4-6-thinking": { maxOutputTokens: 64e3 },
|
|
9299
|
+
"gemini-2.5-flash": { maxOutputTokens: 65536 }
|
|
9300
|
+
};
|
|
9301
|
+
}
|
|
9302
|
+
});
|
|
9303
|
+
|
|
9304
|
+
// packages/agent-runtime/antigravityCloudCodeProvider.ts
|
|
9305
|
+
import { randomUUID } from "node:crypto";
|
|
9306
|
+
function isGemini3WireModel(modelId) {
|
|
9307
|
+
return modelId.includes("gemini-3");
|
|
9308
|
+
}
|
|
9309
|
+
function messageText(content) {
|
|
9310
|
+
if (typeof content === "string") return content;
|
|
9311
|
+
if (!Array.isArray(content)) return "";
|
|
9312
|
+
return content.filter((part) => part?.type === "text").map((part) => part.text).join("\n").trim();
|
|
9313
|
+
}
|
|
9314
|
+
function parseToolArguments2(raw) {
|
|
9315
|
+
if (!raw?.trim()) return {};
|
|
9316
|
+
try {
|
|
9317
|
+
const parsed = JSON.parse(raw);
|
|
9318
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
9319
|
+
} catch {
|
|
9320
|
+
return {};
|
|
9321
|
+
}
|
|
9322
|
+
}
|
|
9323
|
+
function convertOpenAiMessagesToCca(messages, options) {
|
|
9324
|
+
const contents = [];
|
|
9325
|
+
const systemTexts = [];
|
|
9326
|
+
const toolNamesById = /* @__PURE__ */ new Map();
|
|
9327
|
+
for (const raw of messages) {
|
|
9328
|
+
if (!raw || typeof raw !== "object" || !("role" in raw)) continue;
|
|
9329
|
+
const role = String(raw.role);
|
|
9330
|
+
const content = "content" in raw ? raw.content : null;
|
|
9331
|
+
if (role === "system") {
|
|
9332
|
+
const text = messageText(content);
|
|
9333
|
+
if (text) systemTexts.push(text);
|
|
9334
|
+
continue;
|
|
9335
|
+
}
|
|
9336
|
+
if (role === "user") {
|
|
9337
|
+
const text = messageText(content);
|
|
9338
|
+
if (!text) continue;
|
|
9339
|
+
contents.push({ role: "user", parts: [{ text }] });
|
|
9340
|
+
continue;
|
|
9341
|
+
}
|
|
9342
|
+
if (role === "assistant") {
|
|
9343
|
+
const parts = [];
|
|
9344
|
+
const text = messageText(content);
|
|
9345
|
+
if (text) parts.push({ text });
|
|
9346
|
+
const toolCalls = "tool_calls" in raw && Array.isArray(raw.tool_calls) ? raw.tool_calls ?? [] : [];
|
|
9347
|
+
for (const call of toolCalls) {
|
|
9348
|
+
const name = call?.function?.name?.trim();
|
|
9349
|
+
if (!name) continue;
|
|
9350
|
+
const id = call.id?.trim() || `${name}_${toolNamesById.size}`;
|
|
9351
|
+
toolNamesById.set(id, name);
|
|
9352
|
+
parts.push({
|
|
9353
|
+
functionCall: {
|
|
9354
|
+
name,
|
|
9355
|
+
args: parseToolArguments2(call.function?.arguments),
|
|
9356
|
+
id
|
|
9357
|
+
},
|
|
9358
|
+
...options.attachSkipThoughtSignature ? { thoughtSignature: SKIP_THOUGHT_SIGNATURE } : {}
|
|
9359
|
+
});
|
|
9360
|
+
}
|
|
9361
|
+
if (parts.length === 0) continue;
|
|
9362
|
+
contents.push({ role: "model", parts });
|
|
9363
|
+
continue;
|
|
9364
|
+
}
|
|
9365
|
+
if (role === "tool") {
|
|
9366
|
+
const toolCallId = "tool_call_id" in raw && typeof raw.tool_call_id === "string" ? raw.tool_call_id : "";
|
|
9367
|
+
const name = toolNamesById.get(toolCallId) ?? "tool";
|
|
9368
|
+
const output2 = messageText(content) || "{}";
|
|
9369
|
+
contents.push({
|
|
9370
|
+
role: "user",
|
|
9371
|
+
parts: [{ functionResponse: { name, response: { output: output2 } } }]
|
|
9372
|
+
});
|
|
9373
|
+
}
|
|
9374
|
+
}
|
|
9375
|
+
return { contents, systemTexts };
|
|
9376
|
+
}
|
|
9377
|
+
function convertOpenAiTools(tools) {
|
|
9378
|
+
if (!Array.isArray(tools) || tools.length === 0) return void 0;
|
|
9379
|
+
const declarations = [];
|
|
9380
|
+
for (const tool of tools) {
|
|
9381
|
+
if (!tool || typeof tool !== "object" || !("function" in tool)) continue;
|
|
9382
|
+
const fn = tool.function;
|
|
9383
|
+
const name = typeof fn.name === "string" ? fn.name : "";
|
|
9384
|
+
if (!name) continue;
|
|
9385
|
+
declarations.push({
|
|
9386
|
+
name,
|
|
9387
|
+
description: typeof fn.description === "string" ? fn.description : "",
|
|
9388
|
+
parameters: fn.parameters ?? { type: "object", properties: {} }
|
|
9389
|
+
});
|
|
9390
|
+
}
|
|
9391
|
+
if (declarations.length === 0) return void 0;
|
|
9392
|
+
return [{ functionDeclarations: declarations }];
|
|
9393
|
+
}
|
|
9394
|
+
function buildCloudCodeAssistPayload(args2) {
|
|
9395
|
+
const projectId = readAntigravityProjectId(args2.metadata);
|
|
9396
|
+
if (!projectId) {
|
|
9397
|
+
throw new Error(
|
|
9398
|
+
"Antigravity OAuth credential is missing metadata.projectId. Re-run `nolo auth antigravity`."
|
|
9399
|
+
);
|
|
9400
|
+
}
|
|
9401
|
+
const logicalModel = typeof args2.openAiBody.model === "string" && args2.openAiBody.model.trim() || args2.agentConfig.model?.trim() || "gemini-3.1-pro";
|
|
9402
|
+
const { wireModelId: model, profile } = resolveAntigravityWireModel(logicalModel);
|
|
9403
|
+
const rawMessages = Array.isArray(args2.openAiBody.messages) ? args2.openAiBody.messages : [];
|
|
9404
|
+
const { contents, systemTexts } = convertOpenAiMessagesToCca(rawMessages, {
|
|
9405
|
+
attachSkipThoughtSignature: isGemini3WireModel(model)
|
|
9406
|
+
});
|
|
9407
|
+
if (contents.length === 0) {
|
|
9408
|
+
throw new Error("Antigravity Cloud Code Assist request has no user/model contents.");
|
|
9409
|
+
}
|
|
9410
|
+
const prompt = args2.agentConfig.prompt?.trim();
|
|
9411
|
+
if (prompt) systemTexts.unshift(prompt);
|
|
9412
|
+
const request = { contents };
|
|
9413
|
+
if (systemTexts.length > 0) {
|
|
9414
|
+
request.systemInstruction = {
|
|
9415
|
+
role: "user",
|
|
9416
|
+
parts: systemTexts.map((text) => ({ text }))
|
|
9417
|
+
};
|
|
9418
|
+
}
|
|
9419
|
+
const tools = convertOpenAiTools(
|
|
9420
|
+
Array.isArray(args2.openAiBody.tools) ? args2.openAiBody.tools : void 0
|
|
9421
|
+
);
|
|
9422
|
+
if (tools) {
|
|
9423
|
+
request.tools = tools;
|
|
9424
|
+
request.toolConfig = { functionCallingConfig: { mode: "VALIDATED" } };
|
|
9425
|
+
}
|
|
9426
|
+
const generationConfig = {};
|
|
9427
|
+
if (profile?.maxOutputTokens) {
|
|
9428
|
+
generationConfig.maxOutputTokens = profile.maxOutputTokens;
|
|
9429
|
+
} else if (typeof args2.agentConfig.max_tokens === "number" && args2.agentConfig.max_tokens > 0) {
|
|
9430
|
+
generationConfig.maxOutputTokens = args2.agentConfig.max_tokens;
|
|
9431
|
+
}
|
|
9432
|
+
if (typeof args2.agentConfig.temperature === "number") {
|
|
9433
|
+
generationConfig.temperature = args2.agentConfig.temperature;
|
|
9434
|
+
}
|
|
9435
|
+
if (Object.keys(generationConfig).length > 0) {
|
|
9436
|
+
request.generationConfig = generationConfig;
|
|
9437
|
+
}
|
|
9438
|
+
const agentId = randomUUID();
|
|
9439
|
+
const trajectoryId = randomUUID();
|
|
9440
|
+
const step = 2;
|
|
9441
|
+
const requestId = `agent/${agentId}/${Date.now()}/${trajectoryId}/${step}`;
|
|
9442
|
+
const isClaude = model.toLowerCase().includes("claude");
|
|
9443
|
+
const labels = {
|
|
9444
|
+
trajectory_id: trajectoryId,
|
|
9445
|
+
last_step_index: String(step - 1),
|
|
9446
|
+
used_claude: String(isClaude),
|
|
9447
|
+
used_claude_conservative: String(isClaude)
|
|
9448
|
+
};
|
|
9449
|
+
if (profile?.modelEnum) {
|
|
9450
|
+
labels.model_enum = profile.modelEnum;
|
|
9451
|
+
}
|
|
9452
|
+
request.labels = labels;
|
|
9453
|
+
request.sessionId = `-${Math.floor(Math.random() * 9e15)}`;
|
|
9454
|
+
return {
|
|
9455
|
+
url: `${resolveAntigravityCloudCodeBaseUrl(args2.agentConfig.customProviderUrl)}${STREAM_PATH}`,
|
|
9456
|
+
envelope: {
|
|
9457
|
+
project: projectId,
|
|
9458
|
+
model,
|
|
9459
|
+
request,
|
|
9460
|
+
requestId,
|
|
9461
|
+
requestType: "agent",
|
|
9462
|
+
userAgent: "antigravity"
|
|
9463
|
+
}
|
|
9464
|
+
};
|
|
9465
|
+
}
|
|
9466
|
+
function extractJsonFromSseLine(line) {
|
|
9467
|
+
const trimmed = line.trim();
|
|
9468
|
+
if (!trimmed.startsWith("data:")) return null;
|
|
9469
|
+
const payload = trimmed.slice(5).trim();
|
|
9470
|
+
if (!payload || payload === "[DONE]") return null;
|
|
9471
|
+
try {
|
|
9472
|
+
return JSON.parse(payload);
|
|
9473
|
+
} catch {
|
|
9474
|
+
return null;
|
|
9475
|
+
}
|
|
9476
|
+
}
|
|
9477
|
+
function accumulateCcaChunks(chunks) {
|
|
9478
|
+
let text = "";
|
|
9479
|
+
const toolCalls = [];
|
|
9480
|
+
let usage2;
|
|
9481
|
+
for (const chunk of chunks) {
|
|
9482
|
+
if (!chunk || typeof chunk !== "object") continue;
|
|
9483
|
+
const response = "response" in chunk && chunk.response && typeof chunk.response === "object" ? chunk.response : chunk;
|
|
9484
|
+
if ("usageMetadata" in response && response.usageMetadata && typeof response.usageMetadata === "object") {
|
|
9485
|
+
const meta = response.usageMetadata;
|
|
9486
|
+
const prompt = typeof meta.promptTokenCount === "number" ? meta.promptTokenCount : 0;
|
|
9487
|
+
const candidates2 = typeof meta.candidatesTokenCount === "number" ? meta.candidatesTokenCount : 0;
|
|
9488
|
+
const total = typeof meta.totalTokenCount === "number" ? meta.totalTokenCount : prompt + candidates2;
|
|
9489
|
+
usage2 = {
|
|
9490
|
+
prompt_tokens: prompt,
|
|
9491
|
+
completion_tokens: candidates2,
|
|
9492
|
+
total_tokens: total
|
|
9493
|
+
};
|
|
9494
|
+
}
|
|
9495
|
+
const candidates = Array.isArray(response.candidates) ? response.candidates : [];
|
|
9496
|
+
for (const candidate of candidates) {
|
|
9497
|
+
if (!candidate || typeof candidate !== "object" || !("content" in candidate)) continue;
|
|
9498
|
+
const content = candidate.content;
|
|
9499
|
+
if (!content || typeof content !== "object" || !("parts" in content)) continue;
|
|
9500
|
+
const parts = content.parts;
|
|
9501
|
+
if (!Array.isArray(parts)) continue;
|
|
9502
|
+
for (const part of parts) {
|
|
9503
|
+
if (!part || typeof part !== "object") continue;
|
|
9504
|
+
if ("text" in part && typeof part.text === "string") {
|
|
9505
|
+
const piece = part.text;
|
|
9506
|
+
if (!part.thought) {
|
|
9507
|
+
text += piece;
|
|
9508
|
+
}
|
|
9509
|
+
}
|
|
9510
|
+
if ("functionCall" in part && part.functionCall) {
|
|
9511
|
+
const call = part.functionCall;
|
|
9512
|
+
const name = typeof call.name === "string" ? call.name : "tool";
|
|
9513
|
+
const id = typeof call.id === "string" ? call.id : `${name}_${toolCalls.length}`;
|
|
9514
|
+
const argsObj = call.args && typeof call.args === "object" && !Array.isArray(call.args) ? call.args : {};
|
|
9515
|
+
toolCalls.push({
|
|
9516
|
+
id,
|
|
9517
|
+
type: "function",
|
|
9518
|
+
function: { name, arguments: JSON.stringify(argsObj) }
|
|
9519
|
+
});
|
|
9520
|
+
}
|
|
9521
|
+
}
|
|
9522
|
+
}
|
|
9523
|
+
}
|
|
9524
|
+
return { text, toolCalls, usage: usage2 };
|
|
9525
|
+
}
|
|
9526
|
+
async function readSseJsonChunks(response) {
|
|
9527
|
+
const reader = response.body?.getReader();
|
|
9528
|
+
if (!reader) return [];
|
|
9529
|
+
const decoder = new TextDecoder();
|
|
9530
|
+
let buffer = "";
|
|
9531
|
+
const chunks = [];
|
|
9532
|
+
while (true) {
|
|
9533
|
+
const { done, value } = await reader.read();
|
|
9534
|
+
if (done) break;
|
|
9535
|
+
buffer += decoder.decode(value, { stream: true });
|
|
9536
|
+
const lines = buffer.split("\n");
|
|
9537
|
+
buffer = lines.pop() ?? "";
|
|
9538
|
+
for (const line of lines) {
|
|
9539
|
+
const parsed = extractJsonFromSseLine(line);
|
|
9540
|
+
if (parsed) chunks.push(parsed);
|
|
9541
|
+
}
|
|
9542
|
+
}
|
|
9543
|
+
if (buffer.trim()) {
|
|
9544
|
+
const parsed = extractJsonFromSseLine(buffer);
|
|
9545
|
+
if (parsed) chunks.push(parsed);
|
|
9546
|
+
}
|
|
9547
|
+
return chunks;
|
|
9548
|
+
}
|
|
9549
|
+
async function fetchAntigravityCloudCodeCompletion(args2) {
|
|
9550
|
+
const fetchImpl = args2.fetchImpl ?? fetch;
|
|
9551
|
+
const { url, envelope } = buildCloudCodeAssistPayload(args2);
|
|
9552
|
+
const response = await fetchImpl(url, {
|
|
9553
|
+
method: "POST",
|
|
9554
|
+
headers: {
|
|
9555
|
+
Authorization: `Bearer ${args2.accessToken}`,
|
|
9556
|
+
"Content-Type": "application/json",
|
|
9557
|
+
"User-Agent": getAntigravityUserAgent()
|
|
9558
|
+
},
|
|
9559
|
+
body: JSON.stringify(envelope),
|
|
9560
|
+
signal: args2.signal
|
|
9561
|
+
});
|
|
9562
|
+
if (!response.ok) {
|
|
9563
|
+
const errorText = await response.text();
|
|
9564
|
+
return {
|
|
9565
|
+
status: response.status,
|
|
9566
|
+
body: { error: { message: errorText || response.statusText } }
|
|
9567
|
+
};
|
|
9568
|
+
}
|
|
9569
|
+
const chunks = await readSseJsonChunks(response);
|
|
9570
|
+
const { text, toolCalls, usage: usage2 } = accumulateCcaChunks(chunks);
|
|
9571
|
+
const message = {
|
|
9572
|
+
role: "assistant",
|
|
9573
|
+
content: text || null
|
|
9574
|
+
};
|
|
9575
|
+
if (toolCalls.length > 0) {
|
|
9576
|
+
message.tool_calls = toolCalls;
|
|
9577
|
+
}
|
|
9578
|
+
return {
|
|
9579
|
+
status: 200,
|
|
9580
|
+
body: {
|
|
9581
|
+
choices: [
|
|
9582
|
+
{
|
|
9583
|
+
index: 0,
|
|
9584
|
+
message,
|
|
9585
|
+
finish_reason: toolCalls.length > 0 ? "tool_calls" : "stop"
|
|
9586
|
+
}
|
|
9587
|
+
],
|
|
9588
|
+
...usage2 ? { usage: usage2 } : {}
|
|
9589
|
+
}
|
|
9590
|
+
};
|
|
9591
|
+
}
|
|
9592
|
+
var STREAM_PATH, SKIP_THOUGHT_SIGNATURE;
|
|
9593
|
+
var init_antigravityCloudCodeProvider = __esm({
|
|
9594
|
+
"packages/agent-runtime/antigravityCloudCodeProvider.ts"() {
|
|
9595
|
+
"use strict";
|
|
9596
|
+
init_antigravityOAuth();
|
|
9597
|
+
init_antigravityWireModel();
|
|
9598
|
+
STREAM_PATH = "/v1internal:streamGenerateContent?alt=sse";
|
|
9599
|
+
SKIP_THOUGHT_SIGNATURE = "skip_thought_signature_validator";
|
|
9600
|
+
}
|
|
9601
|
+
});
|
|
9602
|
+
|
|
9232
9603
|
// packages/cli/client/agentConfigResolver.ts
|
|
9233
9604
|
var init_agentConfigResolver = __esm({
|
|
9234
9605
|
"packages/cli/client/agentConfigResolver.ts"() {
|
|
@@ -9245,6 +9616,278 @@ var init_localProviderResolver = __esm({
|
|
|
9245
9616
|
}
|
|
9246
9617
|
});
|
|
9247
9618
|
|
|
9619
|
+
// packages/cli/oauth/flows/antigravity.ts
|
|
9620
|
+
function readProjectId(value) {
|
|
9621
|
+
if (typeof value === "string" && value.length > 0) {
|
|
9622
|
+
return value;
|
|
9623
|
+
}
|
|
9624
|
+
if (value && typeof value === "object" && typeof value.id === "string" && value.id.length > 0) {
|
|
9625
|
+
return value.id;
|
|
9626
|
+
}
|
|
9627
|
+
return void 0;
|
|
9628
|
+
}
|
|
9629
|
+
function getDefaultTierId(allowedTiers) {
|
|
9630
|
+
if (!allowedTiers || allowedTiers.length === 0) {
|
|
9631
|
+
return TIER_LEGACY;
|
|
9632
|
+
}
|
|
9633
|
+
const defaultTier = allowedTiers.find(
|
|
9634
|
+
(tier) => tier.isDefault && typeof tier.id === "string" && tier.id.length > 0
|
|
9635
|
+
);
|
|
9636
|
+
if (defaultTier?.id) {
|
|
9637
|
+
return defaultTier.id;
|
|
9638
|
+
}
|
|
9639
|
+
return TIER_LEGACY;
|
|
9640
|
+
}
|
|
9641
|
+
async function sleep2(ms) {
|
|
9642
|
+
const { promise, resolve: resolve8 } = Promise.withResolvers();
|
|
9643
|
+
setTimeout(resolve8, ms);
|
|
9644
|
+
return promise;
|
|
9645
|
+
}
|
|
9646
|
+
async function onboardProjectWithRetries(fetchImpl, endpoint, headers, onboardBody, onProgress) {
|
|
9647
|
+
for (let attempt = 1; attempt <= PROJECT_ONBOARD_MAX_ATTEMPTS; attempt += 1) {
|
|
9648
|
+
if (attempt > 1) {
|
|
9649
|
+
onProgress?.(
|
|
9650
|
+
`Waiting for project provisioning (attempt ${attempt}/${PROJECT_ONBOARD_MAX_ATTEMPTS})...`
|
|
9651
|
+
);
|
|
9652
|
+
await sleep2(PROJECT_ONBOARD_INTERVAL_MS);
|
|
9653
|
+
}
|
|
9654
|
+
const onboardResponse = await fetchImpl(
|
|
9655
|
+
`${endpoint}/v1internal:onboardUser`,
|
|
9656
|
+
{
|
|
9657
|
+
method: "POST",
|
|
9658
|
+
headers,
|
|
9659
|
+
body: JSON.stringify(onboardBody)
|
|
9660
|
+
}
|
|
9661
|
+
);
|
|
9662
|
+
if (!onboardResponse.ok) {
|
|
9663
|
+
const errorText = await onboardResponse.text();
|
|
9664
|
+
throw new Error(
|
|
9665
|
+
`onboardUser failed: ${onboardResponse.status} ${onboardResponse.statusText}: ${errorText}`
|
|
9666
|
+
);
|
|
9667
|
+
}
|
|
9668
|
+
const operation = await onboardResponse.json();
|
|
9669
|
+
if (!operation.done) {
|
|
9670
|
+
continue;
|
|
9671
|
+
}
|
|
9672
|
+
const projectId = readProjectId(operation.response?.cloudaicompanionProject);
|
|
9673
|
+
if (projectId) {
|
|
9674
|
+
return projectId;
|
|
9675
|
+
}
|
|
9676
|
+
}
|
|
9677
|
+
throw new Error(
|
|
9678
|
+
`onboardUser did not return a provisioned project id after ${PROJECT_ONBOARD_MAX_ATTEMPTS} attempts`
|
|
9679
|
+
);
|
|
9680
|
+
}
|
|
9681
|
+
async function discoverProject(fetchImpl, accessToken, onProgress) {
|
|
9682
|
+
const headers = {
|
|
9683
|
+
Authorization: `Bearer ${accessToken}`,
|
|
9684
|
+
"Content-Type": "application/json"
|
|
9685
|
+
};
|
|
9686
|
+
onProgress?.("Checking for existing project...");
|
|
9687
|
+
const endpoint = CLOUD_CODE_ENDPOINT;
|
|
9688
|
+
const loadResponse = await fetchImpl(`${endpoint}/v1internal:loadCodeAssist`, {
|
|
9689
|
+
method: "POST",
|
|
9690
|
+
headers,
|
|
9691
|
+
body: JSON.stringify({
|
|
9692
|
+
metadata: ANTIGRAVITY_LOAD_CODE_ASSIST_METADATA
|
|
9693
|
+
})
|
|
9694
|
+
});
|
|
9695
|
+
if (!loadResponse.ok) {
|
|
9696
|
+
const errorText = await loadResponse.text();
|
|
9697
|
+
throw new Error(
|
|
9698
|
+
`loadCodeAssist failed: ${loadResponse.status} ${loadResponse.statusText}: ${errorText}`
|
|
9699
|
+
);
|
|
9700
|
+
}
|
|
9701
|
+
const loadPayload = await loadResponse.json();
|
|
9702
|
+
const existingProject = readProjectId(loadPayload.cloudaicompanionProject);
|
|
9703
|
+
if (existingProject) {
|
|
9704
|
+
return existingProject;
|
|
9705
|
+
}
|
|
9706
|
+
const tierId = getDefaultTierId(loadPayload.allowedTiers);
|
|
9707
|
+
onProgress?.("Provisioning project...");
|
|
9708
|
+
const onboardBody = {
|
|
9709
|
+
tierId,
|
|
9710
|
+
metadata: ANTIGRAVITY_LOAD_CODE_ASSIST_METADATA
|
|
9711
|
+
};
|
|
9712
|
+
return onboardProjectWithRetries(
|
|
9713
|
+
fetchImpl,
|
|
9714
|
+
endpoint,
|
|
9715
|
+
headers,
|
|
9716
|
+
onboardBody,
|
|
9717
|
+
onProgress
|
|
9718
|
+
);
|
|
9719
|
+
}
|
|
9720
|
+
async function getUserEmail(fetchImpl, accessToken) {
|
|
9721
|
+
try {
|
|
9722
|
+
const response = await fetchImpl(USERINFO_URL, {
|
|
9723
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
9724
|
+
});
|
|
9725
|
+
if (!response.ok) return void 0;
|
|
9726
|
+
const data = await response.json();
|
|
9727
|
+
return typeof data.email === "string" ? data.email : void 0;
|
|
9728
|
+
} catch {
|
|
9729
|
+
return void 0;
|
|
9730
|
+
}
|
|
9731
|
+
}
|
|
9732
|
+
function generateState2() {
|
|
9733
|
+
const bytes = new Uint8Array(16);
|
|
9734
|
+
crypto.getRandomValues(bytes);
|
|
9735
|
+
return Array.from(bytes).map((value) => value.toString(16).padStart(2, "0")).join("");
|
|
9736
|
+
}
|
|
9737
|
+
async function runAntigravityOAuthLogin(deps = {}) {
|
|
9738
|
+
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
9739
|
+
const output2 = deps.output ?? console;
|
|
9740
|
+
const error = deps.error ?? console;
|
|
9741
|
+
const redirectUri = `http://127.0.0.1:${CALLBACK_PORT}${CALLBACK_PATH}`;
|
|
9742
|
+
let handle;
|
|
9743
|
+
try {
|
|
9744
|
+
handle = await startCallbackServer({
|
|
9745
|
+
port: CALLBACK_PORT,
|
|
9746
|
+
hostname: "127.0.0.1",
|
|
9747
|
+
timeoutMs: 5 * 6e4
|
|
9748
|
+
});
|
|
9749
|
+
} catch (err) {
|
|
9750
|
+
throw new Error(
|
|
9751
|
+
`Failed to start Antigravity OAuth callback server on ${CALLBACK_PORT}: ${err instanceof Error ? err.message : String(err)}`
|
|
9752
|
+
);
|
|
9753
|
+
}
|
|
9754
|
+
try {
|
|
9755
|
+
const state = generateState2();
|
|
9756
|
+
const pkce = await generatePkcePair();
|
|
9757
|
+
const authParams = new URLSearchParams({
|
|
9758
|
+
client_id: CLIENT_ID,
|
|
9759
|
+
response_type: "code",
|
|
9760
|
+
redirect_uri: redirectUri,
|
|
9761
|
+
scope: SCOPES.join(" "),
|
|
9762
|
+
state,
|
|
9763
|
+
access_type: "offline",
|
|
9764
|
+
prompt: "consent"
|
|
9765
|
+
});
|
|
9766
|
+
const authUrl = `${AUTH_URL}?${authParams.toString()}`;
|
|
9767
|
+
output2.log(
|
|
9768
|
+
`Open the following URL in your browser to log in to Antigravity:
|
|
9769
|
+
${authUrl}`
|
|
9770
|
+
);
|
|
9771
|
+
if (deps.openBrowser) {
|
|
9772
|
+
try {
|
|
9773
|
+
await deps.openBrowser(authUrl);
|
|
9774
|
+
} catch (err) {
|
|
9775
|
+
error.error(
|
|
9776
|
+
`Failed to open browser automatically: ${err instanceof Error ? err.message : String(err)}`
|
|
9777
|
+
);
|
|
9778
|
+
}
|
|
9779
|
+
}
|
|
9780
|
+
const callback = await handle.waitForCode();
|
|
9781
|
+
const tokenResponse = await fetchImpl(TOKEN_URL, {
|
|
9782
|
+
method: "POST",
|
|
9783
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
9784
|
+
body: new URLSearchParams({
|
|
9785
|
+
client_id: CLIENT_ID,
|
|
9786
|
+
client_secret: CLIENT_SECRET,
|
|
9787
|
+
code: callback.code,
|
|
9788
|
+
grant_type: "authorization_code",
|
|
9789
|
+
redirect_uri: redirectUri
|
|
9790
|
+
})
|
|
9791
|
+
});
|
|
9792
|
+
if (!tokenResponse.ok) {
|
|
9793
|
+
const body = await tokenResponse.text();
|
|
9794
|
+
throw new Error(`Antigravity token exchange failed: ${body}`);
|
|
9795
|
+
}
|
|
9796
|
+
const tokenData = await tokenResponse.json();
|
|
9797
|
+
if (!tokenData.refresh_token) {
|
|
9798
|
+
throw new Error("No refresh token received. Please try again.");
|
|
9799
|
+
}
|
|
9800
|
+
const email = await getUserEmail(fetchImpl, tokenData.access_token);
|
|
9801
|
+
const projectId = await discoverProject(
|
|
9802
|
+
fetchImpl,
|
|
9803
|
+
tokenData.access_token,
|
|
9804
|
+
(message) => output2.log(message)
|
|
9805
|
+
);
|
|
9806
|
+
const now = (deps.now ?? Date.now)();
|
|
9807
|
+
return {
|
|
9808
|
+
provider: "antigravity",
|
|
9809
|
+
accessToken: tokenData.access_token,
|
|
9810
|
+
refreshToken: tokenData.refresh_token,
|
|
9811
|
+
expiresAt: now + tokenData.expires_in * 1e3 - ACCESS_TOKEN_CLIENT_SKEW_MS2,
|
|
9812
|
+
scope: tokenData.scope,
|
|
9813
|
+
obtainedAt: now,
|
|
9814
|
+
metadata: {
|
|
9815
|
+
projectId,
|
|
9816
|
+
email
|
|
9817
|
+
}
|
|
9818
|
+
};
|
|
9819
|
+
} finally {
|
|
9820
|
+
await handle.close();
|
|
9821
|
+
}
|
|
9822
|
+
}
|
|
9823
|
+
async function refreshAntigravityOAuthToken(credential) {
|
|
9824
|
+
if (!credential.refreshToken) {
|
|
9825
|
+
throw new Error("Antigravity credential has no refresh_token");
|
|
9826
|
+
}
|
|
9827
|
+
const fetchImpl = fetch;
|
|
9828
|
+
const projectId = credential.metadata?.projectId ?? void 0;
|
|
9829
|
+
const response = await fetchImpl(TOKEN_URL, {
|
|
9830
|
+
method: "POST",
|
|
9831
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
9832
|
+
body: new URLSearchParams({
|
|
9833
|
+
client_id: CLIENT_ID,
|
|
9834
|
+
client_secret: CLIENT_SECRET,
|
|
9835
|
+
refresh_token: credential.refreshToken,
|
|
9836
|
+
grant_type: "refresh_token"
|
|
9837
|
+
})
|
|
9838
|
+
});
|
|
9839
|
+
if (!response.ok) {
|
|
9840
|
+
const body = await response.text();
|
|
9841
|
+
throw new Error(`Antigravity token refresh failed: ${body}`);
|
|
9842
|
+
}
|
|
9843
|
+
const data = await response.json();
|
|
9844
|
+
const now = Date.now();
|
|
9845
|
+
return {
|
|
9846
|
+
...credential,
|
|
9847
|
+
accessToken: data.access_token,
|
|
9848
|
+
refreshToken: data.refresh_token || credential.refreshToken,
|
|
9849
|
+
expiresAt: now + data.expires_in * 1e3 - ACCESS_TOKEN_CLIENT_SKEW_MS2,
|
|
9850
|
+
scope: data.scope ?? credential.scope,
|
|
9851
|
+
obtainedAt: now
|
|
9852
|
+
};
|
|
9853
|
+
}
|
|
9854
|
+
var decode, CLIENT_ID, CLIENT_SECRET, CALLBACK_PORT, CALLBACK_PATH, SCOPES, AUTH_URL, TOKEN_URL, USERINFO_URL, CLOUD_CODE_ENDPOINT, TIER_LEGACY, PROJECT_ONBOARD_MAX_ATTEMPTS, PROJECT_ONBOARD_INTERVAL_MS, ACCESS_TOKEN_CLIENT_SKEW_MS2, ANTIGRAVITY_LOAD_CODE_ASSIST_METADATA;
|
|
9855
|
+
var init_antigravity = __esm({
|
|
9856
|
+
"packages/cli/oauth/flows/antigravity.ts"() {
|
|
9857
|
+
"use strict";
|
|
9858
|
+
init_callback_server();
|
|
9859
|
+
init_pkce();
|
|
9860
|
+
init_token_store();
|
|
9861
|
+
decode = (s) => Buffer.from(s, "base64").toString("utf8");
|
|
9862
|
+
CLIENT_ID = decode(
|
|
9863
|
+
"MTA3MTAwNjA2MDU5MS10bWhzc2luMmgyMWxjcmUyMzV2dG9sb2poNGc0MDNlcC5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbQ=="
|
|
9864
|
+
);
|
|
9865
|
+
CLIENT_SECRET = decode("R09DU1BYLUs1OEZXUjQ4NkxkTEoxbUxCOHNYQzR6NnFEQWY=");
|
|
9866
|
+
CALLBACK_PORT = 51121;
|
|
9867
|
+
CALLBACK_PATH = "/oauth-callback";
|
|
9868
|
+
SCOPES = [
|
|
9869
|
+
"https://www.googleapis.com/auth/cloud-platform",
|
|
9870
|
+
"https://www.googleapis.com/auth/userinfo.email",
|
|
9871
|
+
"https://www.googleapis.com/auth/userinfo.profile",
|
|
9872
|
+
"https://www.googleapis.com/auth/cclog",
|
|
9873
|
+
"https://www.googleapis.com/auth/experimentsandconfigs"
|
|
9874
|
+
];
|
|
9875
|
+
AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
|
|
9876
|
+
TOKEN_URL = "https://oauth2.googleapis.com/token";
|
|
9877
|
+
USERINFO_URL = "https://www.googleapis.com/oauth2/v1/userinfo?alt=json";
|
|
9878
|
+
CLOUD_CODE_ENDPOINT = "https://cloudcode-pa.googleapis.com";
|
|
9879
|
+
TIER_LEGACY = "legacy-tier";
|
|
9880
|
+
PROJECT_ONBOARD_MAX_ATTEMPTS = 5;
|
|
9881
|
+
PROJECT_ONBOARD_INTERVAL_MS = 2e3;
|
|
9882
|
+
ACCESS_TOKEN_CLIENT_SKEW_MS2 = 5 * 60 * 1e3;
|
|
9883
|
+
ANTIGRAVITY_LOAD_CODE_ASSIST_METADATA = Object.freeze({
|
|
9884
|
+
ideType: "ANTIGRAVITY",
|
|
9885
|
+
platform: "PLATFORM_UNSPECIFIED",
|
|
9886
|
+
pluginType: "GEMINI"
|
|
9887
|
+
});
|
|
9888
|
+
}
|
|
9889
|
+
});
|
|
9890
|
+
|
|
9248
9891
|
// packages/cli/oauth/flows/openai-codex.ts
|
|
9249
9892
|
import { createHash as createHash2 } from "node:crypto";
|
|
9250
9893
|
async function postJson(fetchImpl, url, body, deps) {
|
|
@@ -9597,6 +10240,265 @@ var init_openai_codex = __esm({
|
|
|
9597
10240
|
}
|
|
9598
10241
|
});
|
|
9599
10242
|
|
|
10243
|
+
// packages/cli/oauth/flows/xai.ts
|
|
10244
|
+
function validateXAIEndpoint(url, field) {
|
|
10245
|
+
let parsed;
|
|
10246
|
+
try {
|
|
10247
|
+
parsed = new URL(url);
|
|
10248
|
+
} catch {
|
|
10249
|
+
throw new Error(`Invalid xAI ${field}: ${url}`);
|
|
10250
|
+
}
|
|
10251
|
+
if (parsed.protocol !== "https:") {
|
|
10252
|
+
throw new Error(`Invalid xAI ${field}: ${url}`);
|
|
10253
|
+
}
|
|
10254
|
+
const host = parsed.hostname.toLowerCase();
|
|
10255
|
+
if (!host || host !== "x.ai" && !host.endsWith(".x.ai")) {
|
|
10256
|
+
throw new Error(`Invalid xAI ${field}: ${url}`);
|
|
10257
|
+
}
|
|
10258
|
+
return url;
|
|
10259
|
+
}
|
|
10260
|
+
async function xaiOAuthDiscovery(fetchImpl, timeoutMs = DISCOVERY_TIMEOUT_MS) {
|
|
10261
|
+
let response;
|
|
10262
|
+
try {
|
|
10263
|
+
response = await fetchImpl(XAI_OAUTH_DISCOVERY_URL, {
|
|
10264
|
+
method: "GET",
|
|
10265
|
+
headers: { Accept: "application/json" },
|
|
10266
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
10267
|
+
});
|
|
10268
|
+
} catch (error) {
|
|
10269
|
+
throw new Error(
|
|
10270
|
+
`xAI OIDC discovery failed: ${error instanceof Error ? error.message : String(error)}`
|
|
10271
|
+
);
|
|
10272
|
+
}
|
|
10273
|
+
if (response.status !== 200) {
|
|
10274
|
+
throw new Error(`xAI OIDC discovery returned status ${response.status}.`);
|
|
10275
|
+
}
|
|
10276
|
+
let payload;
|
|
10277
|
+
try {
|
|
10278
|
+
payload = await response.json();
|
|
10279
|
+
} catch (error) {
|
|
10280
|
+
throw new Error(
|
|
10281
|
+
`xAI OIDC discovery returned invalid JSON: ${error instanceof Error ? error.message : String(error)}`
|
|
10282
|
+
);
|
|
10283
|
+
}
|
|
10284
|
+
if (!payload || typeof payload !== "object") {
|
|
10285
|
+
throw new Error("xAI OIDC discovery response was not a JSON object.");
|
|
10286
|
+
}
|
|
10287
|
+
const obj = payload;
|
|
10288
|
+
const authorizationEndpoint = typeof obj.authorization_endpoint === "string" ? obj.authorization_endpoint.trim() : "";
|
|
10289
|
+
const tokenEndpoint = typeof obj.token_endpoint === "string" ? obj.token_endpoint.trim() : "";
|
|
10290
|
+
if (!authorizationEndpoint || !tokenEndpoint) {
|
|
10291
|
+
throw new Error("xAI OIDC discovery response was missing required endpoints.");
|
|
10292
|
+
}
|
|
10293
|
+
validateXAIEndpoint(authorizationEndpoint, "authorization_endpoint");
|
|
10294
|
+
validateXAIEndpoint(tokenEndpoint, "token_endpoint");
|
|
10295
|
+
return {
|
|
10296
|
+
authorization_endpoint: authorizationEndpoint,
|
|
10297
|
+
token_endpoint: tokenEndpoint
|
|
10298
|
+
};
|
|
10299
|
+
}
|
|
10300
|
+
function buildXAIAuthorizeUrl(opts) {
|
|
10301
|
+
const params = new URLSearchParams({
|
|
10302
|
+
response_type: "code",
|
|
10303
|
+
client_id: XAI_OAUTH_CLIENT_ID,
|
|
10304
|
+
redirect_uri: opts.redirectUri,
|
|
10305
|
+
scope: XAI_OAUTH_SCOPE,
|
|
10306
|
+
code_challenge: opts.codeChallenge,
|
|
10307
|
+
code_challenge_method: "S256",
|
|
10308
|
+
state: opts.state,
|
|
10309
|
+
nonce: opts.nonce,
|
|
10310
|
+
plan: "generic",
|
|
10311
|
+
referrer: "nolo-cli"
|
|
10312
|
+
});
|
|
10313
|
+
return `${opts.authorizationEndpoint}?${params.toString()}`;
|
|
10314
|
+
}
|
|
10315
|
+
function generateState3() {
|
|
10316
|
+
const bytes = new Uint8Array(16);
|
|
10317
|
+
crypto.getRandomValues(bytes);
|
|
10318
|
+
return Array.from(bytes).map((value) => value.toString(16).padStart(2, "0")).join("");
|
|
10319
|
+
}
|
|
10320
|
+
async function exchangeXAIToken(fetchImpl, code, redirectUri, verifier) {
|
|
10321
|
+
const discovery = await xaiOAuthDiscovery(fetchImpl);
|
|
10322
|
+
const tokenEndpoint = validateXAIEndpoint(discovery.token_endpoint, "token_endpoint");
|
|
10323
|
+
const body = new URLSearchParams({
|
|
10324
|
+
grant_type: "authorization_code",
|
|
10325
|
+
client_id: XAI_OAUTH_CLIENT_ID,
|
|
10326
|
+
code,
|
|
10327
|
+
redirect_uri: redirectUri,
|
|
10328
|
+
code_verifier: verifier
|
|
10329
|
+
});
|
|
10330
|
+
const response = await fetchImpl(tokenEndpoint, {
|
|
10331
|
+
method: "POST",
|
|
10332
|
+
headers: {
|
|
10333
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
10334
|
+
Accept: "application/json"
|
|
10335
|
+
},
|
|
10336
|
+
body,
|
|
10337
|
+
signal: AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS2)
|
|
10338
|
+
});
|
|
10339
|
+
if (!response.ok) {
|
|
10340
|
+
let detail = "";
|
|
10341
|
+
try {
|
|
10342
|
+
detail = (await response.text()).trim();
|
|
10343
|
+
} catch {
|
|
10344
|
+
}
|
|
10345
|
+
throw new Error(
|
|
10346
|
+
`xAI token exchange failed: ${response.status}${detail ? ` ${detail}` : ""}`
|
|
10347
|
+
);
|
|
10348
|
+
}
|
|
10349
|
+
const data = await response.json();
|
|
10350
|
+
if (typeof data.access_token !== "string" || !data.access_token) {
|
|
10351
|
+
throw new Error("xAI token exchange response missing access_token");
|
|
10352
|
+
}
|
|
10353
|
+
if (typeof data.refresh_token !== "string" || !data.refresh_token) {
|
|
10354
|
+
throw new Error("xAI token exchange response missing refresh_token");
|
|
10355
|
+
}
|
|
10356
|
+
if (typeof data.expires_in !== "number" || !Number.isFinite(data.expires_in)) {
|
|
10357
|
+
throw new Error("xAI token exchange response missing expires_in");
|
|
10358
|
+
}
|
|
10359
|
+
return {
|
|
10360
|
+
accessToken: data.access_token,
|
|
10361
|
+
refreshToken: data.refresh_token,
|
|
10362
|
+
expiresIn: data.expires_in,
|
|
10363
|
+
scope: typeof data.scope === "string" ? data.scope : void 0,
|
|
10364
|
+
idToken: typeof data.id_token === "string" ? data.id_token : void 0
|
|
10365
|
+
};
|
|
10366
|
+
}
|
|
10367
|
+
async function runXaiOAuthLogin(deps = {}) {
|
|
10368
|
+
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
10369
|
+
const output2 = deps.output ?? console;
|
|
10370
|
+
const error = deps.error ?? console;
|
|
10371
|
+
const redirectUri = `http://${XAI_OAUTH_REDIRECT_HOST}:${XAI_OAUTH_REDIRECT_PORT}${XAI_OAUTH_REDIRECT_PATH}`;
|
|
10372
|
+
let handle;
|
|
10373
|
+
try {
|
|
10374
|
+
handle = await startCallbackServer({
|
|
10375
|
+
port: XAI_OAUTH_REDIRECT_PORT,
|
|
10376
|
+
hostname: XAI_OAUTH_REDIRECT_HOST,
|
|
10377
|
+
timeoutMs: 5 * 6e4
|
|
10378
|
+
});
|
|
10379
|
+
} catch (err) {
|
|
10380
|
+
throw new Error(
|
|
10381
|
+
`Failed to start xAI OAuth callback server on ${XAI_OAUTH_REDIRECT_PORT}: ${err instanceof Error ? err.message : String(err)}`
|
|
10382
|
+
);
|
|
10383
|
+
}
|
|
10384
|
+
try {
|
|
10385
|
+
const state = generateState3();
|
|
10386
|
+
const pkce = await generatePkcePair();
|
|
10387
|
+
const nonce = crypto.randomUUID().replace(/-/g, "");
|
|
10388
|
+
const discovery = await xaiOAuthDiscovery(fetchImpl);
|
|
10389
|
+
const authUrl = buildXAIAuthorizeUrl({
|
|
10390
|
+
authorizationEndpoint: discovery.authorization_endpoint,
|
|
10391
|
+
redirectUri,
|
|
10392
|
+
codeChallenge: pkce.challenge,
|
|
10393
|
+
state,
|
|
10394
|
+
nonce
|
|
10395
|
+
});
|
|
10396
|
+
output2.log(
|
|
10397
|
+
`Open the following URL in your browser to log in to xAI Grok (SuperGrok):
|
|
10398
|
+
${authUrl}
|
|
10399
|
+
|
|
10400
|
+
Docs: ${XAI_OAUTH_DOCS_URL}`
|
|
10401
|
+
);
|
|
10402
|
+
if (deps.openBrowser) {
|
|
10403
|
+
try {
|
|
10404
|
+
await deps.openBrowser(authUrl);
|
|
10405
|
+
} catch (err) {
|
|
10406
|
+
error.error(
|
|
10407
|
+
`Failed to open browser automatically: ${err instanceof Error ? err.message : String(err)}`
|
|
10408
|
+
);
|
|
10409
|
+
}
|
|
10410
|
+
}
|
|
10411
|
+
const callback = await handle.waitForCode();
|
|
10412
|
+
const token = await exchangeXAIToken(
|
|
10413
|
+
fetchImpl,
|
|
10414
|
+
callback.code,
|
|
10415
|
+
redirectUri,
|
|
10416
|
+
pkce.verifier
|
|
10417
|
+
);
|
|
10418
|
+
const now = (deps.now ?? Date.now)();
|
|
10419
|
+
const expiresIn = token.expiresIn;
|
|
10420
|
+
return {
|
|
10421
|
+
provider: "xai",
|
|
10422
|
+
accessToken: token.accessToken,
|
|
10423
|
+
refreshToken: token.refreshToken,
|
|
10424
|
+
expiresAt: now + expiresIn * 1e3 - ACCESS_TOKEN_CLIENT_SKEW_MS3,
|
|
10425
|
+
scope: token.scope,
|
|
10426
|
+
idToken: token.idToken,
|
|
10427
|
+
obtainedAt: now
|
|
10428
|
+
};
|
|
10429
|
+
} finally {
|
|
10430
|
+
await handle.close();
|
|
10431
|
+
}
|
|
10432
|
+
}
|
|
10433
|
+
async function refreshXaiOAuthToken(credential) {
|
|
10434
|
+
if (!credential.refreshToken) {
|
|
10435
|
+
throw new Error("xAI credential has no refresh_token");
|
|
10436
|
+
}
|
|
10437
|
+
const fetchImpl = fetch;
|
|
10438
|
+
const discovery = await xaiOAuthDiscovery(fetchImpl);
|
|
10439
|
+
const tokenEndpoint = validateXAIEndpoint(discovery.token_endpoint, "token_endpoint");
|
|
10440
|
+
const body = new URLSearchParams({
|
|
10441
|
+
grant_type: "refresh_token",
|
|
10442
|
+
client_id: XAI_OAUTH_CLIENT_ID,
|
|
10443
|
+
refresh_token: credential.refreshToken
|
|
10444
|
+
});
|
|
10445
|
+
const response = await fetchImpl(tokenEndpoint, {
|
|
10446
|
+
method: "POST",
|
|
10447
|
+
headers: {
|
|
10448
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
10449
|
+
Accept: "application/json"
|
|
10450
|
+
},
|
|
10451
|
+
body,
|
|
10452
|
+
signal: AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS2)
|
|
10453
|
+
});
|
|
10454
|
+
if (!response.ok) {
|
|
10455
|
+
let detail = "";
|
|
10456
|
+
try {
|
|
10457
|
+
detail = (await response.text()).trim();
|
|
10458
|
+
} catch {
|
|
10459
|
+
}
|
|
10460
|
+
throw new Error(
|
|
10461
|
+
`xAI token refresh failed: ${response.status}${detail ? ` ${detail}` : ""}`
|
|
10462
|
+
);
|
|
10463
|
+
}
|
|
10464
|
+
const data = await response.json();
|
|
10465
|
+
if (typeof data.access_token !== "string" || !data.access_token) {
|
|
10466
|
+
throw new Error("xAI token refresh response missing access_token");
|
|
10467
|
+
}
|
|
10468
|
+
if (typeof data.expires_in !== "number" || !Number.isFinite(data.expires_in)) {
|
|
10469
|
+
throw new Error("xAI token refresh response missing expires_in");
|
|
10470
|
+
}
|
|
10471
|
+
const newRefresh = typeof data.refresh_token === "string" && data.refresh_token ? data.refresh_token : credential.refreshToken;
|
|
10472
|
+
const now = Date.now();
|
|
10473
|
+
return {
|
|
10474
|
+
...credential,
|
|
10475
|
+
accessToken: data.access_token,
|
|
10476
|
+
refreshToken: newRefresh,
|
|
10477
|
+
expiresAt: now + data.expires_in * 1e3 - ACCESS_TOKEN_CLIENT_SKEW_MS3,
|
|
10478
|
+
obtainedAt: now
|
|
10479
|
+
};
|
|
10480
|
+
}
|
|
10481
|
+
var XAI_OAUTH_ISSUER, XAI_OAUTH_DISCOVERY_URL, XAI_OAUTH_CLIENT_ID, XAI_OAUTH_SCOPE, XAI_OAUTH_REDIRECT_HOST, XAI_OAUTH_REDIRECT_PORT, XAI_OAUTH_REDIRECT_PATH, XAI_OAUTH_DOCS_URL, ACCESS_TOKEN_CLIENT_SKEW_MS3, DISCOVERY_TIMEOUT_MS, TOKEN_REQUEST_TIMEOUT_MS2;
|
|
10482
|
+
var init_xai = __esm({
|
|
10483
|
+
"packages/cli/oauth/flows/xai.ts"() {
|
|
10484
|
+
"use strict";
|
|
10485
|
+
init_callback_server();
|
|
10486
|
+
init_pkce();
|
|
10487
|
+
init_token_store();
|
|
10488
|
+
XAI_OAUTH_ISSUER = "https://auth.x.ai";
|
|
10489
|
+
XAI_OAUTH_DISCOVERY_URL = `${XAI_OAUTH_ISSUER}/.well-known/openid-configuration`;
|
|
10490
|
+
XAI_OAUTH_CLIENT_ID = "b1a00492-073a-47ea-816f-4c329264a828";
|
|
10491
|
+
XAI_OAUTH_SCOPE = "openid profile email offline_access grok-cli:access api:access";
|
|
10492
|
+
XAI_OAUTH_REDIRECT_HOST = "127.0.0.1";
|
|
10493
|
+
XAI_OAUTH_REDIRECT_PORT = 56121;
|
|
10494
|
+
XAI_OAUTH_REDIRECT_PATH = "/callback";
|
|
10495
|
+
XAI_OAUTH_DOCS_URL = "https://hermes-agent.nousresearch.com/docs/guides/xai-grok-oauth";
|
|
10496
|
+
ACCESS_TOKEN_CLIENT_SKEW_MS3 = 5 * 60 * 1e3;
|
|
10497
|
+
DISCOVERY_TIMEOUT_MS = 15e3;
|
|
10498
|
+
TOKEN_REQUEST_TIMEOUT_MS2 = 2e4;
|
|
10499
|
+
}
|
|
10500
|
+
});
|
|
10501
|
+
|
|
9600
10502
|
// packages/cli/oauth/apiKeyRefResolver.ts
|
|
9601
10503
|
function isOAuthProvider(value) {
|
|
9602
10504
|
return value === "chatgpt" || value === "xai" || value === "antigravity";
|
|
@@ -9606,11 +10508,20 @@ function createOAuthApiKeyRefResolver(options = {}) {
|
|
|
9606
10508
|
const provider = ref.trim();
|
|
9607
10509
|
if (!isOAuthProvider(provider)) return null;
|
|
9608
10510
|
const refresh = REFRESH_BY_PROVIDER[provider];
|
|
9609
|
-
|
|
10511
|
+
const token = await resolveFreshAccessToken({
|
|
9610
10512
|
provider,
|
|
9611
10513
|
...options.homeDir ? { homeDir: options.homeDir } : {},
|
|
9612
10514
|
...refresh ? { refresh } : {}
|
|
9613
10515
|
});
|
|
10516
|
+
if (token) return token;
|
|
10517
|
+
const store = createOAuthTokenStore(options.homeDir);
|
|
10518
|
+
const credential = store.read(provider);
|
|
10519
|
+
if (credential && isTokenExpired(credential)) {
|
|
10520
|
+
throw new Error(
|
|
10521
|
+
`OAuth credential for "${provider}" is expired and could not be refreshed. Run \`nolo auth ${provider}\` (or \`nolo auth ${provider} --sync-to-server\` for server-side runs).`
|
|
10522
|
+
);
|
|
10523
|
+
}
|
|
10524
|
+
return null;
|
|
9614
10525
|
};
|
|
9615
10526
|
}
|
|
9616
10527
|
var REFRESH_BY_PROVIDER;
|
|
@@ -9618,9 +10529,16 @@ var init_apiKeyRefResolver = __esm({
|
|
|
9618
10529
|
"packages/cli/oauth/apiKeyRefResolver.ts"() {
|
|
9619
10530
|
"use strict";
|
|
9620
10531
|
init_token_store();
|
|
10532
|
+
init_antigravity();
|
|
9621
10533
|
init_openai_codex();
|
|
10534
|
+
init_xai();
|
|
9622
10535
|
REFRESH_BY_PROVIDER = {
|
|
9623
|
-
chatgpt: refreshOpenAiCodexToken
|
|
10536
|
+
chatgpt: refreshOpenAiCodexToken,
|
|
10537
|
+
// Previously only chatgpt was wired; expired antigravity/xai tokens then
|
|
10538
|
+
// surfaced as "OAuth credential not found" even when ~/.nolo/credentials
|
|
10539
|
+
// still held a valid refresh_token.
|
|
10540
|
+
antigravity: refreshAntigravityOAuthToken,
|
|
10541
|
+
xai: refreshXaiOAuthToken
|
|
9624
10542
|
};
|
|
9625
10543
|
}
|
|
9626
10544
|
});
|
|
@@ -19152,13 +20070,13 @@ var init_env = __esm({
|
|
|
19152
20070
|
});
|
|
19153
20071
|
|
|
19154
20072
|
// packages/app/utils/retryFetch.ts
|
|
19155
|
-
var TRANSIENT_READ_RETRY_STATUSES, DEFAULT_RETRY_DELAYS_MS,
|
|
20073
|
+
var TRANSIENT_READ_RETRY_STATUSES, DEFAULT_RETRY_DELAYS_MS, sleep3, getRequestMethod, isRetryableReadMethod, isAbortError, fetchWithTransientReadRetry;
|
|
19156
20074
|
var init_retryFetch = __esm({
|
|
19157
20075
|
"packages/app/utils/retryFetch.ts"() {
|
|
19158
20076
|
"use strict";
|
|
19159
20077
|
TRANSIENT_READ_RETRY_STATUSES = /* @__PURE__ */ new Set([502, 503, 504]);
|
|
19160
20078
|
DEFAULT_RETRY_DELAYS_MS = [300, 1e3];
|
|
19161
|
-
|
|
20079
|
+
sleep3 = (ms) => new Promise((resolve8) => {
|
|
19162
20080
|
setTimeout(resolve8, ms);
|
|
19163
20081
|
});
|
|
19164
20082
|
getRequestMethod = (input2, init) => {
|
|
@@ -19176,7 +20094,7 @@ var init_retryFetch = __esm({
|
|
|
19176
20094
|
const delaysMs = options.delaysMs ?? DEFAULT_RETRY_DELAYS_MS;
|
|
19177
20095
|
const retryStatuses = options.retryStatuses ?? TRANSIENT_READ_RETRY_STATUSES;
|
|
19178
20096
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
19179
|
-
const wait = options.sleep ??
|
|
20097
|
+
const wait = options.sleep ?? sleep3;
|
|
19180
20098
|
for (let attempt = 0; ; attempt += 1) {
|
|
19181
20099
|
try {
|
|
19182
20100
|
const response = await fetchImpl(input2, init);
|
|
@@ -25122,12 +26040,12 @@ function dataURLtoFile(dataUrl, filename) {
|
|
|
25122
26040
|
return null;
|
|
25123
26041
|
}
|
|
25124
26042
|
}
|
|
25125
|
-
var BYTES_PER_MB,
|
|
26043
|
+
var BYTES_PER_MB, sleep4, parseDataUrl, appendNoCacheQuery, tryLoadImage, waitForFileReady;
|
|
25126
26044
|
var init_imageUtils = __esm({
|
|
25127
26045
|
"packages/app/utils/imageUtils.ts"() {
|
|
25128
26046
|
"use strict";
|
|
25129
26047
|
BYTES_PER_MB = 1024 * 1024;
|
|
25130
|
-
|
|
26048
|
+
sleep4 = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms));
|
|
25131
26049
|
parseDataUrl = (dataUrl) => {
|
|
25132
26050
|
const trimmed = dataUrl.trim();
|
|
25133
26051
|
const parts = trimmed.split(",");
|
|
@@ -25180,7 +26098,7 @@ var init_imageUtils = __esm({
|
|
|
25180
26098
|
console.debug("[imageUtils] waitForFileReady: image loaded for", url);
|
|
25181
26099
|
return true;
|
|
25182
26100
|
}
|
|
25183
|
-
await
|
|
26101
|
+
await sleep4(intervalMs);
|
|
25184
26102
|
}
|
|
25185
26103
|
console.warn("[imageUtils] waitForFileReady: timeout for", url);
|
|
25186
26104
|
return false;
|
|
@@ -40795,24 +41713,6 @@ var init_generateResponseRequestBody = __esm({
|
|
|
40795
41713
|
}
|
|
40796
41714
|
});
|
|
40797
41715
|
|
|
40798
|
-
// packages/agent-runtime/antigravityOAuth.ts
|
|
40799
|
-
function isAntigravityOAuthAgent(agentConfig) {
|
|
40800
|
-
if (!agentConfig) return false;
|
|
40801
|
-
const apiKeyRef = (agentConfig.apiKeyRef ?? "").trim().toLowerCase();
|
|
40802
|
-
const provider = String(agentConfig.provider ?? "").trim().toLowerCase();
|
|
40803
|
-
const url = (agentConfig.customProviderUrl ?? "").trim().toLowerCase();
|
|
40804
|
-
return apiKeyRef === "antigravity" || provider === "google-antigravity" || url.includes(ANTIGRAVITY_CLOUD_CODE_HOST);
|
|
40805
|
-
}
|
|
40806
|
-
var ANTIGRAVITY_CLOUD_CODE_BASE_URL, ANTIGRAVITY_CLOUD_CODE_HOST;
|
|
40807
|
-
var init_antigravityOAuth = __esm({
|
|
40808
|
-
"packages/agent-runtime/antigravityOAuth.ts"() {
|
|
40809
|
-
"use strict";
|
|
40810
|
-
init_providerResolution();
|
|
40811
|
-
ANTIGRAVITY_CLOUD_CODE_BASE_URL = "https://daily-cloudcode-pa.googleapis.com";
|
|
40812
|
-
ANTIGRAVITY_CLOUD_CODE_HOST = "cloudcode-pa.googleapis.com";
|
|
40813
|
-
}
|
|
40814
|
-
});
|
|
40815
|
-
|
|
40816
41716
|
// packages/agent-runtime/agentCallPlan.ts
|
|
40817
41717
|
function resolveClientWire(plan) {
|
|
40818
41718
|
if (plan.upstreamWire === "gemini-cca") return "chat.completions";
|
|
@@ -51769,7 +52669,7 @@ ${emailPreview(match)}
|
|
|
51769
52669
|
${emailText(match).slice(0, 4e3)}`
|
|
51770
52670
|
};
|
|
51771
52671
|
}
|
|
51772
|
-
await
|
|
52672
|
+
await sleep5(pollIntervalMs);
|
|
51773
52673
|
}
|
|
51774
52674
|
throw new Error(`\u7B49\u5F85\u90AE\u4EF6\u8D85\u65F6\uFF1A${Math.ceil(timeoutMs / 1e3)} \u79D2\u5185\u6CA1\u6709\u5339\u914D\u90AE\u4EF6`);
|
|
51775
52675
|
}
|
|
@@ -51828,7 +52728,7 @@ async function emailArchiveFunc(args2, thunkApi) {
|
|
|
51828
52728
|
displayData: `\u5DF2\u5F52\u6863\u90AE\u4EF6\uFF1A${email?.subject || email?.dbKey}`
|
|
51829
52729
|
};
|
|
51830
52730
|
}
|
|
51831
|
-
var emailPreview,
|
|
52731
|
+
var emailPreview, sleep5, normalizeContains, clampNumber, participantList, emailText, matchesWaitFilters, stripHtml, cleanUrl, extractEmailVerificationArtifacts, emailSearchFunctionSchema, emailReadFunctionSchema, emailUpdateTagsFunctionSchema, emailArchiveFunctionSchema, emailProvisionIdentityFunctionSchema, emailSendFunctionSchema, emailWaitForFunctionSchema, emailExtractVerificationFunctionSchema;
|
|
51832
52732
|
var init_emailTools = __esm({
|
|
51833
52733
|
"packages/ai/tools/emailTools.ts"() {
|
|
51834
52734
|
"use strict";
|
|
@@ -51839,7 +52739,7 @@ var init_emailTools = __esm({
|
|
|
51839
52739
|
const tags = Array.isArray(email?.tags) && email.tags.length > 0 ? ` #${email.tags.join(" #")}` : "";
|
|
51840
52740
|
return `- ${subject} | from: ${from} | ${email?.mailbox ?? "mailbox?"}${tags} | ${email?.dbKey ?? ""}`;
|
|
51841
52741
|
};
|
|
51842
|
-
|
|
52742
|
+
sleep5 = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms));
|
|
51843
52743
|
normalizeContains = (value) => typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
51844
52744
|
clampNumber = (value, fallback, min, max) => {
|
|
51845
52745
|
const parsed = Number(value);
|
|
@@ -61131,7 +62031,7 @@ async function pollAppDeployJob(thunkApi, args2, toolRunId, jobId, options) {
|
|
|
61131
62031
|
);
|
|
61132
62032
|
throw repairError;
|
|
61133
62033
|
}
|
|
61134
|
-
await
|
|
62034
|
+
await sleep6(Math.min(400 + attempt * 50, 2e3));
|
|
61135
62035
|
}
|
|
61136
62036
|
throw new Error("\u90E8\u7F72\u4EFB\u52A1\u4ECD\u5728\u670D\u52A1\u7AEF\u6267\u884C\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u67E5\u770B\u7ED3\u679C\u3002");
|
|
61137
62037
|
} finally {
|
|
@@ -61727,7 +62627,7 @@ async function appFileReplaceFunc(args2, thunkApi) {
|
|
|
61727
62627
|
\u4E0B\u4E00\u6B65\uFF1A\u5148 appPreflight\uFF0C\u518D appDeploy\u3002`
|
|
61728
62628
|
};
|
|
61729
62629
|
}
|
|
61730
|
-
var normalizeOptionalString, TOOL_STEP_STATUS_RANK, APP_DEPLOY_STEP_LABELS,
|
|
62630
|
+
var normalizeOptionalString, TOOL_STEP_STATUS_RANK, APP_DEPLOY_STEP_LABELS, sleep6, appDeployFunctionSchema, appPreflightFunctionSchema, appListFunctionSchema, appDeleteFunctionSchema, appReadFunctionSchema, appFileListFunctionSchema, appFileReadFunctionSchema, appFileSearchFunctionSchema, appFileWriteFunctionSchema, appFileReplaceFunctionSchema;
|
|
61731
62631
|
var init_appTools = __esm({
|
|
61732
62632
|
"packages/ai/tools/appTools.ts"() {
|
|
61733
62633
|
"use strict";
|
|
@@ -61757,7 +62657,7 @@ var init_appTools = __esm({
|
|
|
61757
62657
|
deploy: "\u53D1\u5E03\u7AD9\u70B9",
|
|
61758
62658
|
verify: "\u9A8C\u8BC1\u8BBF\u95EE"
|
|
61759
62659
|
};
|
|
61760
|
-
|
|
62660
|
+
sleep6 = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms));
|
|
61761
62661
|
appDeployFunctionSchema = {
|
|
61762
62662
|
name: "appDeploy",
|
|
61763
62663
|
description: "\u5C06 JavaScript/TypeScript \u4EE3\u7801\u90E8\u7F72\u4E3A Web \u5E94\u7528\u3002\u9ED8\u8BA4\u90E8\u7F72\u5230\u5E73\u53F0\u670D\u52A1\u5668\uFF08nolo.chat/apps/{appId}/\uFF09\uFF0C\u65E0\u9700\u7528\u6237\u914D\u7F6E\u4EFB\u4F55\u989D\u5916\u8D26\u53F7\uFF0C\u7ACB\u5373\u53EF\u8BBF\u95EE\u3002\u4EE3\u7801\u5FC5\u987B\u662F ES Module \u683C\u5F0F\uFF08export default { fetch(req) {} }\uFF09\u3002\u652F\u6301\u591A\u6587\u4EF6\u9879\u76EE\uFF1A\u901A\u8FC7 files \u6570\u7EC4\u4F20\u5165\uFF0C\u670D\u52A1\u7AEF\u81EA\u52A8\u6253\u5305\u3002\u65B0\u5EFA\u5E94\u7528\u65F6\u4F7F\u7528 name\uFF1B\u66F4\u65B0\u5DF2\u6709\u5E94\u7528\u65F6\u5FC5\u987B\u4F18\u5148\u4F20 appId\uFF0C\u907F\u514D\u56E0\u4E3A\u540D\u79F0\u91CD\u590D\u800C\u8BEF\u5EFA\u65B0\u5E94\u7528\u3002",
|
|
@@ -65380,7 +66280,7 @@ __export(cliExecutor_exports, {
|
|
|
65380
66280
|
startCliSession: () => startCliSession
|
|
65381
66281
|
});
|
|
65382
66282
|
import { exec, execSync, spawn as spawn3 } from "child_process";
|
|
65383
|
-
import { randomUUID } from "node:crypto";
|
|
66283
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
65384
66284
|
import { mkdtempSync, readFileSync as readFileSync5, rmSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
65385
66285
|
import { isAbsolute, join as join5, resolve as resolve3 } from "node:path";
|
|
65386
66286
|
import { tmpdir } from "node:os";
|
|
@@ -66530,7 +67430,7 @@ function startCliSession(provider, options = {}) {
|
|
|
66530
67430
|
if (!EXECUTORS[provider]) {
|
|
66531
67431
|
throw new Error(`Unknown CLI provider: "${provider}". Supported: ${Object.keys(EXECUTORS).join(", ")}`);
|
|
66532
67432
|
}
|
|
66533
|
-
const sessionId =
|
|
67433
|
+
const sessionId = randomUUID2();
|
|
66534
67434
|
cliSessions.set(sessionId, {
|
|
66535
67435
|
sessionId,
|
|
66536
67436
|
provider,
|
|
@@ -67846,6 +68746,92 @@ function createCliLocalRuntimeAdapter(deps) {
|
|
|
67846
68746
|
};
|
|
67847
68747
|
}
|
|
67848
68748
|
const apiKeyRefResolver = createOAuthApiKeyRefResolver();
|
|
68749
|
+
if (isAntigravityOAuthAgent(agentConfig)) {
|
|
68750
|
+
const accessToken = await apiKeyRefResolver("antigravity");
|
|
68751
|
+
if (!accessToken) {
|
|
68752
|
+
throw new Error(
|
|
68753
|
+
'OAuth credential for "antigravity" not found locally. Run `nolo auth antigravity`.'
|
|
68754
|
+
);
|
|
68755
|
+
}
|
|
68756
|
+
const credential = readOAuthCredential("antigravity");
|
|
68757
|
+
const { requestedToolNames: requestedToolNames2, tools: tools2 } = resolveProviderOpenAiToolBundle(
|
|
68758
|
+
agentConfig,
|
|
68759
|
+
deps.env,
|
|
68760
|
+
buildProviderOpenAiTools
|
|
68761
|
+
);
|
|
68762
|
+
logLocalRuntimeDiagnostic("provider.selected", {
|
|
68763
|
+
agentKey: agentConfig.key,
|
|
68764
|
+
transport: "antigravity-cloud-code",
|
|
68765
|
+
apiSource: agentConfig.apiSource ?? null,
|
|
68766
|
+
provider: agentConfig.provider ?? "google-antigravity",
|
|
68767
|
+
model: agentConfig.model ?? null,
|
|
68768
|
+
customProviderEndpoint: summarizeEndpoint(agentConfig.customProviderUrl) ?? null,
|
|
68769
|
+
hasApiKey: true,
|
|
68770
|
+
hasProjectId: Boolean(credential?.metadata?.projectId)
|
|
68771
|
+
});
|
|
68772
|
+
return {
|
|
68773
|
+
model: agentConfig.model || "gemini-3.1-pro",
|
|
68774
|
+
complete: async (messages, options) => {
|
|
68775
|
+
const timeoutSignal = buildRequestTimeoutSignal(options?.timeoutMs);
|
|
68776
|
+
const openAiBody = {
|
|
68777
|
+
model: agentConfig.model || "gemini-3.1-pro",
|
|
68778
|
+
messages,
|
|
68779
|
+
stream: false,
|
|
68780
|
+
...tools2.length > 0 ? { tools: tools2 } : {}
|
|
68781
|
+
};
|
|
68782
|
+
logLocalRuntimeDiagnostic("provider.request.start", {
|
|
68783
|
+
agentKey: agentConfig.key,
|
|
68784
|
+
transport: "antigravity-cloud-code",
|
|
68785
|
+
model: openAiBody.model,
|
|
68786
|
+
messageCount: messages.length,
|
|
68787
|
+
toolCount: tools2.length,
|
|
68788
|
+
requestedToolNames: requestedToolNames2,
|
|
68789
|
+
openAiToolNames: summarizeOpenAiToolNames(tools2),
|
|
68790
|
+
timeoutMs: options?.timeoutMs ?? null
|
|
68791
|
+
});
|
|
68792
|
+
try {
|
|
68793
|
+
const result = await fetchAntigravityCloudCodeCompletion({
|
|
68794
|
+
agentConfig,
|
|
68795
|
+
accessToken,
|
|
68796
|
+
metadata: credential?.metadata ?? null,
|
|
68797
|
+
openAiBody,
|
|
68798
|
+
signal: timeoutSignal?.signal,
|
|
68799
|
+
fetchImpl: (url, init) => fetchWithTransientRetry(fetchImpl, url, init, {
|
|
68800
|
+
sleep: deps.sleep,
|
|
68801
|
+
loopbackRequest
|
|
68802
|
+
})
|
|
68803
|
+
});
|
|
68804
|
+
if (result.status < 200 || result.status >= 300) {
|
|
68805
|
+
const errMsg = result.body && typeof result.body === "object" && result.body.error && typeof result.body.error.message === "string" ? result.body.error.message : JSON.stringify(result.body);
|
|
68806
|
+
throw new Error(`local antigravity provider failed: HTTP ${result.status} ${errMsg}`);
|
|
68807
|
+
}
|
|
68808
|
+
const choice = Array.isArray(result.body.choices) ? result.body.choices[0] : void 0;
|
|
68809
|
+
const message = choice?.message ?? {};
|
|
68810
|
+
const content = typeof message.content === "string" ? message.content : message.content == null ? "" : String(message.content);
|
|
68811
|
+
const tool_calls = Array.isArray(message.tool_calls) ? message.tool_calls : void 0;
|
|
68812
|
+
if (content && options?.onTextDelta) {
|
|
68813
|
+
options.onTextDelta(content);
|
|
68814
|
+
}
|
|
68815
|
+
logLocalRuntimeDiagnostic("provider.request.result", {
|
|
68816
|
+
agentKey: agentConfig.key,
|
|
68817
|
+
transport: "antigravity-cloud-code",
|
|
68818
|
+
ok: true,
|
|
68819
|
+
contentChars: content.length,
|
|
68820
|
+
toolCallCount: tool_calls?.length ?? 0
|
|
68821
|
+
});
|
|
68822
|
+
return {
|
|
68823
|
+
content,
|
|
68824
|
+
model: agentConfig.model || "gemini-3.1-pro",
|
|
68825
|
+
provider: agentConfig.provider || "google-antigravity",
|
|
68826
|
+
...tool_calls ? { tool_calls } : {},
|
|
68827
|
+
trace: messages
|
|
68828
|
+
};
|
|
68829
|
+
} finally {
|
|
68830
|
+
timeoutSignal?.clear();
|
|
68831
|
+
}
|
|
68832
|
+
}
|
|
68833
|
+
};
|
|
68834
|
+
}
|
|
67849
68835
|
if (shouldUsePlatformChatProvider(deps.env, agentConfig)) {
|
|
67850
68836
|
const providerConfig2 = await resolvePlatformChatProviderConfig({
|
|
67851
68837
|
agentConfig,
|
|
@@ -68075,6 +69061,9 @@ var init_localRuntimeAdapter = __esm({
|
|
|
68075
69061
|
"packages/cli/client/localRuntimeAdapter.ts"() {
|
|
68076
69062
|
"use strict";
|
|
68077
69063
|
init_agentRuntimeLocal();
|
|
69064
|
+
init_antigravityCloudCodeProvider();
|
|
69065
|
+
init_antigravityOAuth();
|
|
69066
|
+
init_oauthTokenStore();
|
|
68078
69067
|
init_localRuntimeDb();
|
|
68079
69068
|
init_agentConfigResolver();
|
|
68080
69069
|
init_localProviderResolver();
|
|
@@ -69170,7 +70159,7 @@ __export(machineInfo_exports, {
|
|
|
69170
70159
|
import { existsSync as existsSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3 } from "node:fs";
|
|
69171
70160
|
import { dirname as dirname4, join as join8 } from "node:path";
|
|
69172
70161
|
import { arch as arch2, hostname as hostname2, homedir as homedir5, platform } from "node:os";
|
|
69173
|
-
import { randomUUID as
|
|
70162
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
69174
70163
|
function defaultMachineIdPath() {
|
|
69175
70164
|
return join8(homedir5(), ".nolo", "machine-id");
|
|
69176
70165
|
}
|
|
@@ -69180,7 +70169,7 @@ function resolveMachineId(path8 = defaultMachineIdPath()) {
|
|
|
69180
70169
|
const existing = readFileSync7(path8, "utf8").trim();
|
|
69181
70170
|
if (existing) return existing;
|
|
69182
70171
|
}
|
|
69183
|
-
const next = `machine-${
|
|
70172
|
+
const next = `machine-${randomUUID3()}`;
|
|
69184
70173
|
mkdirSync3(dirname4(path8), { recursive: true });
|
|
69185
70174
|
writeFileSync4(path8, `${next}
|
|
69186
70175
|
`, "utf8");
|
|
@@ -69576,22 +70565,22 @@ async function runHttpAgentTurn(options, authToken) {
|
|
|
69576
70565
|
options.output.write(`[nolo] Agent request failed: HTTP ${res.status}
|
|
69577
70566
|
`);
|
|
69578
70567
|
const errorText = typeof data?.error === "string" ? data.error.trim() : "";
|
|
69579
|
-
const
|
|
70568
|
+
const messageText2 = typeof data?.message === "string" ? data.message.trim() : "";
|
|
69580
70569
|
const reasonText = typeof data?.reason === "string" ? data.reason.trim() : "";
|
|
69581
70570
|
const codeText = typeof data?.code === "string" ? data.code.trim() : "";
|
|
69582
70571
|
const dialogIdText = typeof data?.dialogId === "string" ? data.dialogId.trim() : "";
|
|
69583
|
-
if (errorText ||
|
|
69584
|
-
options.output.write(`${errorText ||
|
|
70572
|
+
if (errorText || messageText2) {
|
|
70573
|
+
options.output.write(`${errorText || messageText2}
|
|
69585
70574
|
`);
|
|
69586
|
-
if (
|
|
69587
|
-
options.output.write(`${
|
|
70575
|
+
if (messageText2 && messageText2 !== errorText) {
|
|
70576
|
+
options.output.write(`${messageText2}
|
|
69588
70577
|
`);
|
|
69589
70578
|
}
|
|
69590
|
-
if (codeText && codeText !== errorText && codeText !==
|
|
70579
|
+
if (codeText && codeText !== errorText && codeText !== messageText2) {
|
|
69591
70580
|
options.output.write(`code=${codeText}
|
|
69592
70581
|
`);
|
|
69593
70582
|
}
|
|
69594
|
-
if (reasonText && reasonText !== errorText && reasonText !==
|
|
70583
|
+
if (reasonText && reasonText !== errorText && reasonText !== messageText2) {
|
|
69595
70584
|
options.output.write(`reason=${reasonText}
|
|
69596
70585
|
`);
|
|
69597
70586
|
}
|
|
@@ -76671,458 +77660,6 @@ var init_spaceCommands = __esm({
|
|
|
76671
77660
|
}
|
|
76672
77661
|
});
|
|
76673
77662
|
|
|
76674
|
-
// packages/cli/oauth/flows/antigravity.ts
|
|
76675
|
-
function readProjectId(value) {
|
|
76676
|
-
if (typeof value === "string" && value.length > 0) {
|
|
76677
|
-
return value;
|
|
76678
|
-
}
|
|
76679
|
-
if (value && typeof value === "object" && typeof value.id === "string" && value.id.length > 0) {
|
|
76680
|
-
return value.id;
|
|
76681
|
-
}
|
|
76682
|
-
return void 0;
|
|
76683
|
-
}
|
|
76684
|
-
function getDefaultTierId(allowedTiers) {
|
|
76685
|
-
if (!allowedTiers || allowedTiers.length === 0) {
|
|
76686
|
-
return TIER_LEGACY;
|
|
76687
|
-
}
|
|
76688
|
-
const defaultTier = allowedTiers.find(
|
|
76689
|
-
(tier) => tier.isDefault && typeof tier.id === "string" && tier.id.length > 0
|
|
76690
|
-
);
|
|
76691
|
-
if (defaultTier?.id) {
|
|
76692
|
-
return defaultTier.id;
|
|
76693
|
-
}
|
|
76694
|
-
return TIER_LEGACY;
|
|
76695
|
-
}
|
|
76696
|
-
async function sleep6(ms) {
|
|
76697
|
-
const { promise, resolve: resolve8 } = Promise.withResolvers();
|
|
76698
|
-
setTimeout(resolve8, ms);
|
|
76699
|
-
return promise;
|
|
76700
|
-
}
|
|
76701
|
-
async function onboardProjectWithRetries(fetchImpl, endpoint, headers, onboardBody, onProgress) {
|
|
76702
|
-
for (let attempt = 1; attempt <= PROJECT_ONBOARD_MAX_ATTEMPTS; attempt += 1) {
|
|
76703
|
-
if (attempt > 1) {
|
|
76704
|
-
onProgress?.(
|
|
76705
|
-
`Waiting for project provisioning (attempt ${attempt}/${PROJECT_ONBOARD_MAX_ATTEMPTS})...`
|
|
76706
|
-
);
|
|
76707
|
-
await sleep6(PROJECT_ONBOARD_INTERVAL_MS);
|
|
76708
|
-
}
|
|
76709
|
-
const onboardResponse = await fetchImpl(
|
|
76710
|
-
`${endpoint}/v1internal:onboardUser`,
|
|
76711
|
-
{
|
|
76712
|
-
method: "POST",
|
|
76713
|
-
headers,
|
|
76714
|
-
body: JSON.stringify(onboardBody)
|
|
76715
|
-
}
|
|
76716
|
-
);
|
|
76717
|
-
if (!onboardResponse.ok) {
|
|
76718
|
-
const errorText = await onboardResponse.text();
|
|
76719
|
-
throw new Error(
|
|
76720
|
-
`onboardUser failed: ${onboardResponse.status} ${onboardResponse.statusText}: ${errorText}`
|
|
76721
|
-
);
|
|
76722
|
-
}
|
|
76723
|
-
const operation = await onboardResponse.json();
|
|
76724
|
-
if (!operation.done) {
|
|
76725
|
-
continue;
|
|
76726
|
-
}
|
|
76727
|
-
const projectId = readProjectId(operation.response?.cloudaicompanionProject);
|
|
76728
|
-
if (projectId) {
|
|
76729
|
-
return projectId;
|
|
76730
|
-
}
|
|
76731
|
-
}
|
|
76732
|
-
throw new Error(
|
|
76733
|
-
`onboardUser did not return a provisioned project id after ${PROJECT_ONBOARD_MAX_ATTEMPTS} attempts`
|
|
76734
|
-
);
|
|
76735
|
-
}
|
|
76736
|
-
async function discoverProject(fetchImpl, accessToken, onProgress) {
|
|
76737
|
-
const headers = {
|
|
76738
|
-
Authorization: `Bearer ${accessToken}`,
|
|
76739
|
-
"Content-Type": "application/json"
|
|
76740
|
-
};
|
|
76741
|
-
onProgress?.("Checking for existing project...");
|
|
76742
|
-
const endpoint = CLOUD_CODE_ENDPOINT;
|
|
76743
|
-
const loadResponse = await fetchImpl(`${endpoint}/v1internal:loadCodeAssist`, {
|
|
76744
|
-
method: "POST",
|
|
76745
|
-
headers,
|
|
76746
|
-
body: JSON.stringify({
|
|
76747
|
-
metadata: ANTIGRAVITY_LOAD_CODE_ASSIST_METADATA
|
|
76748
|
-
})
|
|
76749
|
-
});
|
|
76750
|
-
if (!loadResponse.ok) {
|
|
76751
|
-
const errorText = await loadResponse.text();
|
|
76752
|
-
throw new Error(
|
|
76753
|
-
`loadCodeAssist failed: ${loadResponse.status} ${loadResponse.statusText}: ${errorText}`
|
|
76754
|
-
);
|
|
76755
|
-
}
|
|
76756
|
-
const loadPayload = await loadResponse.json();
|
|
76757
|
-
const existingProject = readProjectId(loadPayload.cloudaicompanionProject);
|
|
76758
|
-
if (existingProject) {
|
|
76759
|
-
return existingProject;
|
|
76760
|
-
}
|
|
76761
|
-
const tierId = getDefaultTierId(loadPayload.allowedTiers);
|
|
76762
|
-
onProgress?.("Provisioning project...");
|
|
76763
|
-
const onboardBody = {
|
|
76764
|
-
tierId,
|
|
76765
|
-
metadata: ANTIGRAVITY_LOAD_CODE_ASSIST_METADATA
|
|
76766
|
-
};
|
|
76767
|
-
return onboardProjectWithRetries(
|
|
76768
|
-
fetchImpl,
|
|
76769
|
-
endpoint,
|
|
76770
|
-
headers,
|
|
76771
|
-
onboardBody,
|
|
76772
|
-
onProgress
|
|
76773
|
-
);
|
|
76774
|
-
}
|
|
76775
|
-
async function getUserEmail(fetchImpl, accessToken) {
|
|
76776
|
-
try {
|
|
76777
|
-
const response = await fetchImpl(USERINFO_URL, {
|
|
76778
|
-
headers: { Authorization: `Bearer ${accessToken}` }
|
|
76779
|
-
});
|
|
76780
|
-
if (!response.ok) return void 0;
|
|
76781
|
-
const data = await response.json();
|
|
76782
|
-
return typeof data.email === "string" ? data.email : void 0;
|
|
76783
|
-
} catch {
|
|
76784
|
-
return void 0;
|
|
76785
|
-
}
|
|
76786
|
-
}
|
|
76787
|
-
function generateState2() {
|
|
76788
|
-
const bytes = new Uint8Array(16);
|
|
76789
|
-
crypto.getRandomValues(bytes);
|
|
76790
|
-
return Array.from(bytes).map((value) => value.toString(16).padStart(2, "0")).join("");
|
|
76791
|
-
}
|
|
76792
|
-
async function runAntigravityOAuthLogin(deps = {}) {
|
|
76793
|
-
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
76794
|
-
const output2 = deps.output ?? console;
|
|
76795
|
-
const error = deps.error ?? console;
|
|
76796
|
-
const redirectUri = `http://127.0.0.1:${CALLBACK_PORT}${CALLBACK_PATH}`;
|
|
76797
|
-
let handle;
|
|
76798
|
-
try {
|
|
76799
|
-
handle = await startCallbackServer({
|
|
76800
|
-
port: CALLBACK_PORT,
|
|
76801
|
-
hostname: "127.0.0.1",
|
|
76802
|
-
timeoutMs: 5 * 6e4
|
|
76803
|
-
});
|
|
76804
|
-
} catch (err) {
|
|
76805
|
-
throw new Error(
|
|
76806
|
-
`Failed to start Antigravity OAuth callback server on ${CALLBACK_PORT}: ${err instanceof Error ? err.message : String(err)}`
|
|
76807
|
-
);
|
|
76808
|
-
}
|
|
76809
|
-
try {
|
|
76810
|
-
const state = generateState2();
|
|
76811
|
-
const pkce = await generatePkcePair();
|
|
76812
|
-
const authParams = new URLSearchParams({
|
|
76813
|
-
client_id: CLIENT_ID,
|
|
76814
|
-
response_type: "code",
|
|
76815
|
-
redirect_uri: redirectUri,
|
|
76816
|
-
scope: SCOPES.join(" "),
|
|
76817
|
-
state,
|
|
76818
|
-
access_type: "offline",
|
|
76819
|
-
prompt: "consent"
|
|
76820
|
-
});
|
|
76821
|
-
const authUrl = `${AUTH_URL}?${authParams.toString()}`;
|
|
76822
|
-
output2.log(
|
|
76823
|
-
`Open the following URL in your browser to log in to Antigravity:
|
|
76824
|
-
${authUrl}`
|
|
76825
|
-
);
|
|
76826
|
-
if (deps.openBrowser) {
|
|
76827
|
-
try {
|
|
76828
|
-
await deps.openBrowser(authUrl);
|
|
76829
|
-
} catch (err) {
|
|
76830
|
-
error.error(
|
|
76831
|
-
`Failed to open browser automatically: ${err instanceof Error ? err.message : String(err)}`
|
|
76832
|
-
);
|
|
76833
|
-
}
|
|
76834
|
-
}
|
|
76835
|
-
const callback = await handle.waitForCode();
|
|
76836
|
-
const tokenResponse = await fetchImpl(TOKEN_URL, {
|
|
76837
|
-
method: "POST",
|
|
76838
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
76839
|
-
body: new URLSearchParams({
|
|
76840
|
-
client_id: CLIENT_ID,
|
|
76841
|
-
client_secret: CLIENT_SECRET,
|
|
76842
|
-
code: callback.code,
|
|
76843
|
-
grant_type: "authorization_code",
|
|
76844
|
-
redirect_uri: redirectUri
|
|
76845
|
-
})
|
|
76846
|
-
});
|
|
76847
|
-
if (!tokenResponse.ok) {
|
|
76848
|
-
const body = await tokenResponse.text();
|
|
76849
|
-
throw new Error(`Antigravity token exchange failed: ${body}`);
|
|
76850
|
-
}
|
|
76851
|
-
const tokenData = await tokenResponse.json();
|
|
76852
|
-
if (!tokenData.refresh_token) {
|
|
76853
|
-
throw new Error("No refresh token received. Please try again.");
|
|
76854
|
-
}
|
|
76855
|
-
const email = await getUserEmail(fetchImpl, tokenData.access_token);
|
|
76856
|
-
const projectId = await discoverProject(
|
|
76857
|
-
fetchImpl,
|
|
76858
|
-
tokenData.access_token,
|
|
76859
|
-
(message) => output2.log(message)
|
|
76860
|
-
);
|
|
76861
|
-
const now = (deps.now ?? Date.now)();
|
|
76862
|
-
return {
|
|
76863
|
-
provider: "antigravity",
|
|
76864
|
-
accessToken: tokenData.access_token,
|
|
76865
|
-
refreshToken: tokenData.refresh_token,
|
|
76866
|
-
expiresAt: now + tokenData.expires_in * 1e3 - ACCESS_TOKEN_CLIENT_SKEW_MS2,
|
|
76867
|
-
scope: tokenData.scope,
|
|
76868
|
-
obtainedAt: now,
|
|
76869
|
-
metadata: {
|
|
76870
|
-
projectId,
|
|
76871
|
-
email
|
|
76872
|
-
}
|
|
76873
|
-
};
|
|
76874
|
-
} finally {
|
|
76875
|
-
await handle.close();
|
|
76876
|
-
}
|
|
76877
|
-
}
|
|
76878
|
-
var decode, CLIENT_ID, CLIENT_SECRET, CALLBACK_PORT, CALLBACK_PATH, SCOPES, AUTH_URL, TOKEN_URL, USERINFO_URL, CLOUD_CODE_ENDPOINT, TIER_LEGACY, PROJECT_ONBOARD_MAX_ATTEMPTS, PROJECT_ONBOARD_INTERVAL_MS, ACCESS_TOKEN_CLIENT_SKEW_MS2, ANTIGRAVITY_LOAD_CODE_ASSIST_METADATA;
|
|
76879
|
-
var init_antigravity = __esm({
|
|
76880
|
-
"packages/cli/oauth/flows/antigravity.ts"() {
|
|
76881
|
-
"use strict";
|
|
76882
|
-
init_callback_server();
|
|
76883
|
-
init_pkce();
|
|
76884
|
-
init_token_store();
|
|
76885
|
-
decode = (s) => Buffer.from(s, "base64").toString("utf8");
|
|
76886
|
-
CLIENT_ID = decode(
|
|
76887
|
-
"MTA3MTAwNjA2MDU5MS10bWhzc2luMmgyMWxjcmUyMzV2dG9sb2poNGc0MDNlcC5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbQ=="
|
|
76888
|
-
);
|
|
76889
|
-
CLIENT_SECRET = decode("R09DU1BYLUs1OEZXUjQ4NkxkTEoxbUxCOHNYQzR6NnFEQWY=");
|
|
76890
|
-
CALLBACK_PORT = 51121;
|
|
76891
|
-
CALLBACK_PATH = "/oauth-callback";
|
|
76892
|
-
SCOPES = [
|
|
76893
|
-
"https://www.googleapis.com/auth/cloud-platform",
|
|
76894
|
-
"https://www.googleapis.com/auth/userinfo.email",
|
|
76895
|
-
"https://www.googleapis.com/auth/userinfo.profile",
|
|
76896
|
-
"https://www.googleapis.com/auth/cclog",
|
|
76897
|
-
"https://www.googleapis.com/auth/experimentsandconfigs"
|
|
76898
|
-
];
|
|
76899
|
-
AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
|
|
76900
|
-
TOKEN_URL = "https://oauth2.googleapis.com/token";
|
|
76901
|
-
USERINFO_URL = "https://www.googleapis.com/oauth2/v1/userinfo?alt=json";
|
|
76902
|
-
CLOUD_CODE_ENDPOINT = "https://cloudcode-pa.googleapis.com";
|
|
76903
|
-
TIER_LEGACY = "legacy-tier";
|
|
76904
|
-
PROJECT_ONBOARD_MAX_ATTEMPTS = 5;
|
|
76905
|
-
PROJECT_ONBOARD_INTERVAL_MS = 2e3;
|
|
76906
|
-
ACCESS_TOKEN_CLIENT_SKEW_MS2 = 5 * 60 * 1e3;
|
|
76907
|
-
ANTIGRAVITY_LOAD_CODE_ASSIST_METADATA = Object.freeze({
|
|
76908
|
-
ideType: "ANTIGRAVITY",
|
|
76909
|
-
platform: "PLATFORM_UNSPECIFIED",
|
|
76910
|
-
pluginType: "GEMINI"
|
|
76911
|
-
});
|
|
76912
|
-
}
|
|
76913
|
-
});
|
|
76914
|
-
|
|
76915
|
-
// packages/cli/oauth/flows/xai.ts
|
|
76916
|
-
function validateXAIEndpoint(url, field) {
|
|
76917
|
-
let parsed;
|
|
76918
|
-
try {
|
|
76919
|
-
parsed = new URL(url);
|
|
76920
|
-
} catch {
|
|
76921
|
-
throw new Error(`Invalid xAI ${field}: ${url}`);
|
|
76922
|
-
}
|
|
76923
|
-
if (parsed.protocol !== "https:") {
|
|
76924
|
-
throw new Error(`Invalid xAI ${field}: ${url}`);
|
|
76925
|
-
}
|
|
76926
|
-
const host = parsed.hostname.toLowerCase();
|
|
76927
|
-
if (!host || host !== "x.ai" && !host.endsWith(".x.ai")) {
|
|
76928
|
-
throw new Error(`Invalid xAI ${field}: ${url}`);
|
|
76929
|
-
}
|
|
76930
|
-
return url;
|
|
76931
|
-
}
|
|
76932
|
-
async function xaiOAuthDiscovery(fetchImpl, timeoutMs = DISCOVERY_TIMEOUT_MS) {
|
|
76933
|
-
let response;
|
|
76934
|
-
try {
|
|
76935
|
-
response = await fetchImpl(XAI_OAUTH_DISCOVERY_URL, {
|
|
76936
|
-
method: "GET",
|
|
76937
|
-
headers: { Accept: "application/json" },
|
|
76938
|
-
signal: AbortSignal.timeout(timeoutMs)
|
|
76939
|
-
});
|
|
76940
|
-
} catch (error) {
|
|
76941
|
-
throw new Error(
|
|
76942
|
-
`xAI OIDC discovery failed: ${error instanceof Error ? error.message : String(error)}`
|
|
76943
|
-
);
|
|
76944
|
-
}
|
|
76945
|
-
if (response.status !== 200) {
|
|
76946
|
-
throw new Error(`xAI OIDC discovery returned status ${response.status}.`);
|
|
76947
|
-
}
|
|
76948
|
-
let payload;
|
|
76949
|
-
try {
|
|
76950
|
-
payload = await response.json();
|
|
76951
|
-
} catch (error) {
|
|
76952
|
-
throw new Error(
|
|
76953
|
-
`xAI OIDC discovery returned invalid JSON: ${error instanceof Error ? error.message : String(error)}`
|
|
76954
|
-
);
|
|
76955
|
-
}
|
|
76956
|
-
if (!payload || typeof payload !== "object") {
|
|
76957
|
-
throw new Error("xAI OIDC discovery response was not a JSON object.");
|
|
76958
|
-
}
|
|
76959
|
-
const obj = payload;
|
|
76960
|
-
const authorizationEndpoint = typeof obj.authorization_endpoint === "string" ? obj.authorization_endpoint.trim() : "";
|
|
76961
|
-
const tokenEndpoint = typeof obj.token_endpoint === "string" ? obj.token_endpoint.trim() : "";
|
|
76962
|
-
if (!authorizationEndpoint || !tokenEndpoint) {
|
|
76963
|
-
throw new Error("xAI OIDC discovery response was missing required endpoints.");
|
|
76964
|
-
}
|
|
76965
|
-
validateXAIEndpoint(authorizationEndpoint, "authorization_endpoint");
|
|
76966
|
-
validateXAIEndpoint(tokenEndpoint, "token_endpoint");
|
|
76967
|
-
return {
|
|
76968
|
-
authorization_endpoint: authorizationEndpoint,
|
|
76969
|
-
token_endpoint: tokenEndpoint
|
|
76970
|
-
};
|
|
76971
|
-
}
|
|
76972
|
-
function buildXAIAuthorizeUrl(opts) {
|
|
76973
|
-
const params = new URLSearchParams({
|
|
76974
|
-
response_type: "code",
|
|
76975
|
-
client_id: XAI_OAUTH_CLIENT_ID,
|
|
76976
|
-
redirect_uri: opts.redirectUri,
|
|
76977
|
-
scope: XAI_OAUTH_SCOPE,
|
|
76978
|
-
code_challenge: opts.codeChallenge,
|
|
76979
|
-
code_challenge_method: "S256",
|
|
76980
|
-
state: opts.state,
|
|
76981
|
-
nonce: opts.nonce,
|
|
76982
|
-
plan: "generic",
|
|
76983
|
-
referrer: "nolo-cli"
|
|
76984
|
-
});
|
|
76985
|
-
return `${opts.authorizationEndpoint}?${params.toString()}`;
|
|
76986
|
-
}
|
|
76987
|
-
function generateState3() {
|
|
76988
|
-
const bytes = new Uint8Array(16);
|
|
76989
|
-
crypto.getRandomValues(bytes);
|
|
76990
|
-
return Array.from(bytes).map((value) => value.toString(16).padStart(2, "0")).join("");
|
|
76991
|
-
}
|
|
76992
|
-
async function exchangeXAIToken(fetchImpl, code, redirectUri, verifier) {
|
|
76993
|
-
const discovery = await xaiOAuthDiscovery(fetchImpl);
|
|
76994
|
-
const tokenEndpoint = validateXAIEndpoint(discovery.token_endpoint, "token_endpoint");
|
|
76995
|
-
const body = new URLSearchParams({
|
|
76996
|
-
grant_type: "authorization_code",
|
|
76997
|
-
client_id: XAI_OAUTH_CLIENT_ID,
|
|
76998
|
-
code,
|
|
76999
|
-
redirect_uri: redirectUri,
|
|
77000
|
-
code_verifier: verifier
|
|
77001
|
-
});
|
|
77002
|
-
const response = await fetchImpl(tokenEndpoint, {
|
|
77003
|
-
method: "POST",
|
|
77004
|
-
headers: {
|
|
77005
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
77006
|
-
Accept: "application/json"
|
|
77007
|
-
},
|
|
77008
|
-
body,
|
|
77009
|
-
signal: AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS2)
|
|
77010
|
-
});
|
|
77011
|
-
if (!response.ok) {
|
|
77012
|
-
let detail = "";
|
|
77013
|
-
try {
|
|
77014
|
-
detail = (await response.text()).trim();
|
|
77015
|
-
} catch {
|
|
77016
|
-
}
|
|
77017
|
-
throw new Error(
|
|
77018
|
-
`xAI token exchange failed: ${response.status}${detail ? ` ${detail}` : ""}`
|
|
77019
|
-
);
|
|
77020
|
-
}
|
|
77021
|
-
const data = await response.json();
|
|
77022
|
-
if (typeof data.access_token !== "string" || !data.access_token) {
|
|
77023
|
-
throw new Error("xAI token exchange response missing access_token");
|
|
77024
|
-
}
|
|
77025
|
-
if (typeof data.refresh_token !== "string" || !data.refresh_token) {
|
|
77026
|
-
throw new Error("xAI token exchange response missing refresh_token");
|
|
77027
|
-
}
|
|
77028
|
-
if (typeof data.expires_in !== "number" || !Number.isFinite(data.expires_in)) {
|
|
77029
|
-
throw new Error("xAI token exchange response missing expires_in");
|
|
77030
|
-
}
|
|
77031
|
-
return {
|
|
77032
|
-
accessToken: data.access_token,
|
|
77033
|
-
refreshToken: data.refresh_token,
|
|
77034
|
-
expiresIn: data.expires_in,
|
|
77035
|
-
scope: typeof data.scope === "string" ? data.scope : void 0,
|
|
77036
|
-
idToken: typeof data.id_token === "string" ? data.id_token : void 0
|
|
77037
|
-
};
|
|
77038
|
-
}
|
|
77039
|
-
async function runXaiOAuthLogin(deps = {}) {
|
|
77040
|
-
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
77041
|
-
const output2 = deps.output ?? console;
|
|
77042
|
-
const error = deps.error ?? console;
|
|
77043
|
-
const redirectUri = `http://${XAI_OAUTH_REDIRECT_HOST}:${XAI_OAUTH_REDIRECT_PORT}${XAI_OAUTH_REDIRECT_PATH}`;
|
|
77044
|
-
let handle;
|
|
77045
|
-
try {
|
|
77046
|
-
handle = await startCallbackServer({
|
|
77047
|
-
port: XAI_OAUTH_REDIRECT_PORT,
|
|
77048
|
-
hostname: XAI_OAUTH_REDIRECT_HOST,
|
|
77049
|
-
timeoutMs: 5 * 6e4
|
|
77050
|
-
});
|
|
77051
|
-
} catch (err) {
|
|
77052
|
-
throw new Error(
|
|
77053
|
-
`Failed to start xAI OAuth callback server on ${XAI_OAUTH_REDIRECT_PORT}: ${err instanceof Error ? err.message : String(err)}`
|
|
77054
|
-
);
|
|
77055
|
-
}
|
|
77056
|
-
try {
|
|
77057
|
-
const state = generateState3();
|
|
77058
|
-
const pkce = await generatePkcePair();
|
|
77059
|
-
const nonce = crypto.randomUUID().replace(/-/g, "");
|
|
77060
|
-
const discovery = await xaiOAuthDiscovery(fetchImpl);
|
|
77061
|
-
const authUrl = buildXAIAuthorizeUrl({
|
|
77062
|
-
authorizationEndpoint: discovery.authorization_endpoint,
|
|
77063
|
-
redirectUri,
|
|
77064
|
-
codeChallenge: pkce.challenge,
|
|
77065
|
-
state,
|
|
77066
|
-
nonce
|
|
77067
|
-
});
|
|
77068
|
-
output2.log(
|
|
77069
|
-
`Open the following URL in your browser to log in to xAI Grok (SuperGrok):
|
|
77070
|
-
${authUrl}
|
|
77071
|
-
|
|
77072
|
-
Docs: ${XAI_OAUTH_DOCS_URL}`
|
|
77073
|
-
);
|
|
77074
|
-
if (deps.openBrowser) {
|
|
77075
|
-
try {
|
|
77076
|
-
await deps.openBrowser(authUrl);
|
|
77077
|
-
} catch (err) {
|
|
77078
|
-
error.error(
|
|
77079
|
-
`Failed to open browser automatically: ${err instanceof Error ? err.message : String(err)}`
|
|
77080
|
-
);
|
|
77081
|
-
}
|
|
77082
|
-
}
|
|
77083
|
-
const callback = await handle.waitForCode();
|
|
77084
|
-
const token = await exchangeXAIToken(
|
|
77085
|
-
fetchImpl,
|
|
77086
|
-
callback.code,
|
|
77087
|
-
redirectUri,
|
|
77088
|
-
pkce.verifier
|
|
77089
|
-
);
|
|
77090
|
-
const now = (deps.now ?? Date.now)();
|
|
77091
|
-
const expiresIn = token.expiresIn;
|
|
77092
|
-
return {
|
|
77093
|
-
provider: "xai",
|
|
77094
|
-
accessToken: token.accessToken,
|
|
77095
|
-
refreshToken: token.refreshToken,
|
|
77096
|
-
expiresAt: now + expiresIn * 1e3 - ACCESS_TOKEN_CLIENT_SKEW_MS3,
|
|
77097
|
-
scope: token.scope,
|
|
77098
|
-
idToken: token.idToken,
|
|
77099
|
-
obtainedAt: now
|
|
77100
|
-
};
|
|
77101
|
-
} finally {
|
|
77102
|
-
await handle.close();
|
|
77103
|
-
}
|
|
77104
|
-
}
|
|
77105
|
-
var XAI_OAUTH_ISSUER, XAI_OAUTH_DISCOVERY_URL, XAI_OAUTH_CLIENT_ID, XAI_OAUTH_SCOPE, XAI_OAUTH_REDIRECT_HOST, XAI_OAUTH_REDIRECT_PORT, XAI_OAUTH_REDIRECT_PATH, XAI_OAUTH_DOCS_URL, ACCESS_TOKEN_CLIENT_SKEW_MS3, DISCOVERY_TIMEOUT_MS, TOKEN_REQUEST_TIMEOUT_MS2;
|
|
77106
|
-
var init_xai = __esm({
|
|
77107
|
-
"packages/cli/oauth/flows/xai.ts"() {
|
|
77108
|
-
"use strict";
|
|
77109
|
-
init_callback_server();
|
|
77110
|
-
init_pkce();
|
|
77111
|
-
init_token_store();
|
|
77112
|
-
XAI_OAUTH_ISSUER = "https://auth.x.ai";
|
|
77113
|
-
XAI_OAUTH_DISCOVERY_URL = `${XAI_OAUTH_ISSUER}/.well-known/openid-configuration`;
|
|
77114
|
-
XAI_OAUTH_CLIENT_ID = "b1a00492-073a-47ea-816f-4c329264a828";
|
|
77115
|
-
XAI_OAUTH_SCOPE = "openid profile email offline_access grok-cli:access api:access";
|
|
77116
|
-
XAI_OAUTH_REDIRECT_HOST = "127.0.0.1";
|
|
77117
|
-
XAI_OAUTH_REDIRECT_PORT = 56121;
|
|
77118
|
-
XAI_OAUTH_REDIRECT_PATH = "/callback";
|
|
77119
|
-
XAI_OAUTH_DOCS_URL = "https://hermes-agent.nousresearch.com/docs/guides/xai-grok-oauth";
|
|
77120
|
-
ACCESS_TOKEN_CLIENT_SKEW_MS3 = 5 * 60 * 1e3;
|
|
77121
|
-
DISCOVERY_TIMEOUT_MS = 15e3;
|
|
77122
|
-
TOKEN_REQUEST_TIMEOUT_MS2 = 2e4;
|
|
77123
|
-
}
|
|
77124
|
-
});
|
|
77125
|
-
|
|
77126
77663
|
// packages/cli/client/profileConfig.ts
|
|
77127
77664
|
import { existsSync as existsSync10, mkdirSync as mkdirSync5, readFileSync as readFileSync11, writeFileSync as writeFileSync6 } from "node:fs";
|
|
77128
77665
|
import { dirname as dirname5, join as join11 } from "node:path";
|