nolo-cli 0.1.52 → 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.
Files changed (2) hide show
  1. package/index.js +1220 -514
  2. 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
- return resolveFreshAccessToken({
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, sleep2, getRequestMethod, isRetryableReadMethod, isAbortError, fetchWithTransientReadRetry;
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
- sleep2 = (ms) => new Promise((resolve8) => {
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 ?? sleep2;
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, sleep3, parseDataUrl, appendNoCacheQuery, tryLoadImage, waitForFileReady;
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
- sleep3 = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms));
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 sleep3(intervalMs);
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 sleep4(pollIntervalMs);
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, sleep4, normalizeContains, clampNumber, participantList, emailText, matchesWaitFilters, stripHtml, cleanUrl, extractEmailVerificationArtifacts, emailSearchFunctionSchema, emailReadFunctionSchema, emailUpdateTagsFunctionSchema, emailArchiveFunctionSchema, emailProvisionIdentityFunctionSchema, emailSendFunctionSchema, emailWaitForFunctionSchema, emailExtractVerificationFunctionSchema;
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
- sleep4 = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms));
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 sleep5(Math.min(400 + attempt * 50, 2e3));
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, sleep5, appDeployFunctionSchema, appPreflightFunctionSchema, appListFunctionSchema, appDeleteFunctionSchema, appReadFunctionSchema, appFileListFunctionSchema, appFileReadFunctionSchema, appFileSearchFunctionSchema, appFileWriteFunctionSchema, appFileReplaceFunctionSchema;
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
- sleep5 = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms));
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 = randomUUID();
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 randomUUID2 } from "node:crypto";
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-${randomUUID2()}`;
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 messageText = typeof data?.message === "string" ? data.message.trim() : "";
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 || messageText) {
69584
- options.output.write(`${errorText || messageText}
70572
+ if (errorText || messageText2) {
70573
+ options.output.write(`${errorText || messageText2}
69585
70574
  `);
69586
- if (messageText && messageText !== errorText) {
69587
- options.output.write(`${messageText}
70575
+ if (messageText2 && messageText2 !== errorText) {
70576
+ options.output.write(`${messageText2}
69588
70577
  `);
69589
70578
  }
69590
- if (codeText && codeText !== errorText && codeText !== messageText) {
70579
+ if (codeText && codeText !== errorText && codeText !== messageText2) {
69591
70580
  options.output.write(`code=${codeText}
69592
70581
  `);
69593
70582
  }
69594
- if (reasonText && reasonText !== errorText && reasonText !== messageText) {
70583
+ if (reasonText && reasonText !== errorText && reasonText !== messageText2) {
69595
70584
  options.output.write(`reason=${reasonText}
69596
70585
  `);
69597
70586
  }
@@ -70008,10 +70997,12 @@ ${this.text}
70008
70997
  // packages/cli/agentRunControl.ts
70009
70998
  var agentRunControl_exports = {};
70010
70999
  __export(agentRunControl_exports, {
71000
+ checkStaleRun: () => checkStaleRun,
70011
71001
  defaultGenerateRunId: () => defaultGenerateRunId,
70012
71002
  finalizeRunRecord: () => finalizeRunRecord,
70013
71003
  findRunRecord: () => findRunRecord,
70014
71004
  findRunRecordByPid: () => findRunRecordByPid,
71005
+ isPidGone: () => isPidGone,
70015
71006
  listRunRecords: () => listRunRecords,
70016
71007
  readRunRecord: () => readRunRecord,
70017
71008
  resolveNoloHome: () => resolveNoloHome2,
@@ -70054,7 +71045,7 @@ function defaultGenerateRunId() {
70054
71045
  function writeRunRecord(record, deps = {}) {
70055
71046
  const fs5 = deps.fs ?? nodeFs;
70056
71047
  const path8 = resolveRunRecordPath(record.runId, deps.env, deps.homedir);
70057
- fs5.mkdirSync(join9(path8, ".."), { recursive: true });
71048
+ fs5.mkdirSync(resolveRunsDir(deps.env, deps.homedir), { recursive: true });
70058
71049
  fs5.writeFileSync(path8, JSON.stringify(record, null, 2));
70059
71050
  }
70060
71051
  function readRunRecord(runId, deps = {}) {
@@ -70172,6 +71163,29 @@ function finalizeRunRecord(runId, update, deps = {}) {
70172
71163
  record.endedAt = now().toISOString();
70173
71164
  writeRunRecord(record, deps);
70174
71165
  }
71166
+ function isPidGone(pid, deps = {}) {
71167
+ const kill = deps.kill ?? ((p, s) => process.kill(p, s));
71168
+ try {
71169
+ kill(pid, "0");
71170
+ return false;
71171
+ } catch (error) {
71172
+ const code = error.code;
71173
+ return code === "ESRCH";
71174
+ }
71175
+ }
71176
+ function checkStaleRun(runId, deps = {}) {
71177
+ const record = readRunRecord(runId, deps);
71178
+ if (!record) return null;
71179
+ if (record.status !== "running") return record;
71180
+ if (typeof record.pid !== "number") return record;
71181
+ if (!isPidGone(record.pid, deps)) return record;
71182
+ const now = deps.now ?? (() => /* @__PURE__ */ new Date());
71183
+ record.status = "failed";
71184
+ record.note = "process gone: pid no longer exists";
71185
+ record.endedAt = now().toISOString();
71186
+ writeRunRecord(record, deps);
71187
+ return record;
71188
+ }
70175
71189
  function formatDuration(startedAt, endedAt) {
70176
71190
  const start = new Date(startedAt).getTime();
70177
71191
  const end = endedAt ? new Date(endedAt).getTime() : Date.now();
@@ -70213,14 +71227,48 @@ function readLogContent(logPath, tailCount, deps) {
70213
71227
  return "";
70214
71228
  }
70215
71229
  }
70216
- async function runAgentPsCommand(_args, deps) {
71230
+ function isRunningStatus(status) {
71231
+ return RUNNING_STATUSES.has(status);
71232
+ }
71233
+ function parseJsonFlag(args2) {
71234
+ let json = false;
71235
+ const rest = [];
71236
+ for (const arg of args2) {
71237
+ if (arg === "--json") {
71238
+ json = true;
71239
+ continue;
71240
+ }
71241
+ if (arg.startsWith("--json=")) {
71242
+ const value = arg.slice("--json=".length);
71243
+ json = value === "" || value === "true" || value === "1";
71244
+ continue;
71245
+ }
71246
+ rest.push(arg);
71247
+ }
71248
+ return { json, rest };
71249
+ }
71250
+ function defaultSleep2(ms) {
71251
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
71252
+ }
71253
+ async function runAgentPsCommand(args2, deps) {
71254
+ const { json } = parseJsonFlag(args2);
70217
71255
  const records = listRunRecords(deps);
70218
- if (records.length === 0) {
71256
+ for (const record of records) {
71257
+ if (record.status === "running" && typeof record.pid === "number") {
71258
+ checkStaleRun(record.runId, deps);
71259
+ }
71260
+ }
71261
+ const refreshed = records.map((r) => readRunRecord(r.runId, deps)).filter(Boolean);
71262
+ if (json) {
71263
+ deps.output.write(JSON.stringify(refreshed) + "\n");
71264
+ return 0;
71265
+ }
71266
+ if (refreshed.length === 0) {
70219
71267
  deps.output.write("No local runs found.\n");
70220
71268
  return 0;
70221
71269
  }
70222
71270
  deps.output.write("RUN ID STATUS PID AGENT\n");
70223
- for (const record of records) {
71271
+ for (const record of refreshed) {
70224
71272
  const pid = record.pid?.toString() ?? "-";
70225
71273
  deps.output.write(
70226
71274
  `${record.runId.padEnd(32)} ${record.status.padEnd(8)} ${pid.padEnd(8)} ${record.agentKey}
@@ -70229,18 +71277,83 @@ async function runAgentPsCommand(_args, deps) {
70229
71277
  }
70230
71278
  return 0;
70231
71279
  }
71280
+ function parseStatusArgs(args2) {
71281
+ let target = "";
71282
+ let json = false;
71283
+ let watch = false;
71284
+ let intervalMs = 2e3;
71285
+ for (let i = 0; i < args2.length; i++) {
71286
+ const arg = args2[i];
71287
+ if (arg === "--json") {
71288
+ json = true;
71289
+ continue;
71290
+ }
71291
+ if (arg.startsWith("--json=")) {
71292
+ const value = arg.slice("--json=".length);
71293
+ json = value === "" || value === "true" || value === "1";
71294
+ continue;
71295
+ }
71296
+ if (arg === "--watch") {
71297
+ watch = true;
71298
+ continue;
71299
+ }
71300
+ if (arg.startsWith("--watch=")) {
71301
+ const value = arg.slice("--watch=".length);
71302
+ watch = value === "" || value === "true" || value === "1";
71303
+ continue;
71304
+ }
71305
+ if (arg === "--interval-ms") {
71306
+ const next = args2[i + 1];
71307
+ if (next && /^\d+$/.test(next)) {
71308
+ intervalMs = Number(next);
71309
+ i += 1;
71310
+ }
71311
+ continue;
71312
+ }
71313
+ if (arg.startsWith("--interval-ms=")) {
71314
+ const value = arg.slice("--interval-ms=".length);
71315
+ if (/^\d+$/.test(value)) intervalMs = Number(value);
71316
+ continue;
71317
+ }
71318
+ if (!arg.startsWith("-") && !target) {
71319
+ target = arg;
71320
+ }
71321
+ }
71322
+ return { target, json, watch, intervalMs };
71323
+ }
71324
+ function printStatusTick(record, deps) {
71325
+ const elapsed = formatDuration(record.startedAt, record.endedAt);
71326
+ const note = record.note ? ` (${record.note})` : "";
71327
+ deps.output.write(
71328
+ `[${(/* @__PURE__ */ new Date()).toISOString()}] ${record.runId} status=${record.status} elapsed=${elapsed}${note}
71329
+ `
71330
+ );
71331
+ }
70232
71332
  async function runAgentStatusCommand(args2, deps) {
70233
- const target = args2[0];
71333
+ const { target, json, watch, intervalMs } = parseStatusArgs(args2);
70234
71334
  if (!target) {
70235
- deps.output.write("Usage: nolo agent status <runId|pid>\n");
71335
+ deps.output.write("Usage: nolo agent status <runId|pid> [--json] [--watch] [--interval-ms N]\n");
70236
71336
  return 1;
70237
71337
  }
70238
- const record = findRunRecord(target, deps);
70239
- if (!record) {
71338
+ const initial = findRunRecord(target, deps);
71339
+ if (!initial) {
70240
71340
  deps.output.write(`Run not found: ${target}
70241
71341
  `);
70242
71342
  return 1;
70243
71343
  }
71344
+ const reconciled = checkStaleRun(initial.runId, deps) ?? initial;
71345
+ if (json) {
71346
+ const record = readRunRecord(reconciled.runId, deps) ?? reconciled;
71347
+ deps.output.write(JSON.stringify(record) + "\n");
71348
+ return 0;
71349
+ }
71350
+ if (!watch) {
71351
+ const record = readRunRecord(reconciled.runId, deps) ?? reconciled;
71352
+ return printStatusOnce(record, deps);
71353
+ }
71354
+ return runStatusWatch(reconciled.runId, intervalMs, deps);
71355
+ }
71356
+ function printStatusOnce(record, deps) {
70244
71357
  deps.output.write(`runId: ${record.runId}
70245
71358
  `);
70246
71359
  deps.output.write(`status: ${record.status}
@@ -70260,6 +71373,8 @@ async function runAgentStatusCommand(args2, deps) {
70260
71373
  if (typeof record.exitCode === "number") deps.output.write(`exitCode: ${record.exitCode}
70261
71374
  `);
70262
71375
  if (record.dialogId) deps.output.write(`dialog: ${record.dialogId}
71376
+ `);
71377
+ if (record.note) deps.output.write(`note: ${record.note}
70263
71378
  `);
70264
71379
  deps.output.write(`log: ${record.logPath}
70265
71380
  `);
@@ -70273,6 +71388,47 @@ async function runAgentStatusCommand(args2, deps) {
70273
71388
  }
70274
71389
  return 0;
70275
71390
  }
71391
+ async function runStatusWatch(runId, intervalMs, deps) {
71392
+ const sleep7 = deps.sleep ?? defaultSleep2;
71393
+ const now = deps.now ?? (() => /* @__PURE__ */ new Date());
71394
+ let stopped = false;
71395
+ const setSignalHandler = deps.setSignalHandler ?? ((handler) => {
71396
+ process.once("SIGINT", handler);
71397
+ });
71398
+ const clearSignalHandler = deps.clearSignalHandler ?? (() => {
71399
+ process.removeAllListeners("SIGINT");
71400
+ });
71401
+ setSignalHandler(() => {
71402
+ stopped = true;
71403
+ });
71404
+ try {
71405
+ let record = readRunRecord(runId, deps);
71406
+ if (!record) {
71407
+ deps.output.write(`Run not found: ${runId}
71408
+ `);
71409
+ return 1;
71410
+ }
71411
+ printStatusTick(record, deps);
71412
+ while (!stopped && isRunningStatus(record.status)) {
71413
+ await sleep7(intervalMs);
71414
+ if (stopped) break;
71415
+ record = checkStaleRun(runId, deps);
71416
+ if (!record) {
71417
+ deps.output.write(`Run not found: ${runId}
71418
+ `);
71419
+ return 1;
71420
+ }
71421
+ printStatusTick(record, deps);
71422
+ }
71423
+ if (stopped) {
71424
+ deps.output.write(`watch stopped by signal
71425
+ `);
71426
+ }
71427
+ return 0;
71428
+ } finally {
71429
+ clearSignalHandler();
71430
+ }
71431
+ }
70276
71432
  function parseLogsArgs(args2, onTail) {
70277
71433
  let runId = "";
70278
71434
  for (let i = 0; i < args2.length; i++) {
@@ -70364,10 +71520,12 @@ async function runAgentStopCommand(args2, deps) {
70364
71520
  async function runAgentKillCommand(args2, deps) {
70365
71521
  return runSignalCommand(args2, "SIGKILL", "kill", deps);
70366
71522
  }
71523
+ var RUNNING_STATUSES;
70367
71524
  var init_agentRunControl = __esm({
70368
71525
  "packages/cli/agentRunControl.ts"() {
70369
71526
  "use strict";
70370
71527
  init_cliEnvHelpers();
71528
+ RUNNING_STATUSES = /* @__PURE__ */ new Set(["running"]);
70371
71529
  }
70372
71530
  });
70373
71531
 
@@ -76502,458 +77660,6 @@ var init_spaceCommands = __esm({
76502
77660
  }
76503
77661
  });
76504
77662
 
76505
- // packages/cli/oauth/flows/antigravity.ts
76506
- function readProjectId(value) {
76507
- if (typeof value === "string" && value.length > 0) {
76508
- return value;
76509
- }
76510
- if (value && typeof value === "object" && typeof value.id === "string" && value.id.length > 0) {
76511
- return value.id;
76512
- }
76513
- return void 0;
76514
- }
76515
- function getDefaultTierId(allowedTiers) {
76516
- if (!allowedTiers || allowedTiers.length === 0) {
76517
- return TIER_LEGACY;
76518
- }
76519
- const defaultTier = allowedTiers.find(
76520
- (tier) => tier.isDefault && typeof tier.id === "string" && tier.id.length > 0
76521
- );
76522
- if (defaultTier?.id) {
76523
- return defaultTier.id;
76524
- }
76525
- return TIER_LEGACY;
76526
- }
76527
- async function sleep6(ms) {
76528
- const { promise, resolve: resolve8 } = Promise.withResolvers();
76529
- setTimeout(resolve8, ms);
76530
- return promise;
76531
- }
76532
- async function onboardProjectWithRetries(fetchImpl, endpoint, headers, onboardBody, onProgress) {
76533
- for (let attempt = 1; attempt <= PROJECT_ONBOARD_MAX_ATTEMPTS; attempt += 1) {
76534
- if (attempt > 1) {
76535
- onProgress?.(
76536
- `Waiting for project provisioning (attempt ${attempt}/${PROJECT_ONBOARD_MAX_ATTEMPTS})...`
76537
- );
76538
- await sleep6(PROJECT_ONBOARD_INTERVAL_MS);
76539
- }
76540
- const onboardResponse = await fetchImpl(
76541
- `${endpoint}/v1internal:onboardUser`,
76542
- {
76543
- method: "POST",
76544
- headers,
76545
- body: JSON.stringify(onboardBody)
76546
- }
76547
- );
76548
- if (!onboardResponse.ok) {
76549
- const errorText = await onboardResponse.text();
76550
- throw new Error(
76551
- `onboardUser failed: ${onboardResponse.status} ${onboardResponse.statusText}: ${errorText}`
76552
- );
76553
- }
76554
- const operation = await onboardResponse.json();
76555
- if (!operation.done) {
76556
- continue;
76557
- }
76558
- const projectId = readProjectId(operation.response?.cloudaicompanionProject);
76559
- if (projectId) {
76560
- return projectId;
76561
- }
76562
- }
76563
- throw new Error(
76564
- `onboardUser did not return a provisioned project id after ${PROJECT_ONBOARD_MAX_ATTEMPTS} attempts`
76565
- );
76566
- }
76567
- async function discoverProject(fetchImpl, accessToken, onProgress) {
76568
- const headers = {
76569
- Authorization: `Bearer ${accessToken}`,
76570
- "Content-Type": "application/json"
76571
- };
76572
- onProgress?.("Checking for existing project...");
76573
- const endpoint = CLOUD_CODE_ENDPOINT;
76574
- const loadResponse = await fetchImpl(`${endpoint}/v1internal:loadCodeAssist`, {
76575
- method: "POST",
76576
- headers,
76577
- body: JSON.stringify({
76578
- metadata: ANTIGRAVITY_LOAD_CODE_ASSIST_METADATA
76579
- })
76580
- });
76581
- if (!loadResponse.ok) {
76582
- const errorText = await loadResponse.text();
76583
- throw new Error(
76584
- `loadCodeAssist failed: ${loadResponse.status} ${loadResponse.statusText}: ${errorText}`
76585
- );
76586
- }
76587
- const loadPayload = await loadResponse.json();
76588
- const existingProject = readProjectId(loadPayload.cloudaicompanionProject);
76589
- if (existingProject) {
76590
- return existingProject;
76591
- }
76592
- const tierId = getDefaultTierId(loadPayload.allowedTiers);
76593
- onProgress?.("Provisioning project...");
76594
- const onboardBody = {
76595
- tierId,
76596
- metadata: ANTIGRAVITY_LOAD_CODE_ASSIST_METADATA
76597
- };
76598
- return onboardProjectWithRetries(
76599
- fetchImpl,
76600
- endpoint,
76601
- headers,
76602
- onboardBody,
76603
- onProgress
76604
- );
76605
- }
76606
- async function getUserEmail(fetchImpl, accessToken) {
76607
- try {
76608
- const response = await fetchImpl(USERINFO_URL, {
76609
- headers: { Authorization: `Bearer ${accessToken}` }
76610
- });
76611
- if (!response.ok) return void 0;
76612
- const data = await response.json();
76613
- return typeof data.email === "string" ? data.email : void 0;
76614
- } catch {
76615
- return void 0;
76616
- }
76617
- }
76618
- function generateState2() {
76619
- const bytes = new Uint8Array(16);
76620
- crypto.getRandomValues(bytes);
76621
- return Array.from(bytes).map((value) => value.toString(16).padStart(2, "0")).join("");
76622
- }
76623
- async function runAntigravityOAuthLogin(deps = {}) {
76624
- const fetchImpl = deps.fetchImpl ?? fetch;
76625
- const output2 = deps.output ?? console;
76626
- const error = deps.error ?? console;
76627
- const redirectUri = `http://127.0.0.1:${CALLBACK_PORT}${CALLBACK_PATH}`;
76628
- let handle;
76629
- try {
76630
- handle = await startCallbackServer({
76631
- port: CALLBACK_PORT,
76632
- hostname: "127.0.0.1",
76633
- timeoutMs: 5 * 6e4
76634
- });
76635
- } catch (err) {
76636
- throw new Error(
76637
- `Failed to start Antigravity OAuth callback server on ${CALLBACK_PORT}: ${err instanceof Error ? err.message : String(err)}`
76638
- );
76639
- }
76640
- try {
76641
- const state = generateState2();
76642
- const pkce = await generatePkcePair();
76643
- const authParams = new URLSearchParams({
76644
- client_id: CLIENT_ID,
76645
- response_type: "code",
76646
- redirect_uri: redirectUri,
76647
- scope: SCOPES.join(" "),
76648
- state,
76649
- access_type: "offline",
76650
- prompt: "consent"
76651
- });
76652
- const authUrl = `${AUTH_URL}?${authParams.toString()}`;
76653
- output2.log(
76654
- `Open the following URL in your browser to log in to Antigravity:
76655
- ${authUrl}`
76656
- );
76657
- if (deps.openBrowser) {
76658
- try {
76659
- await deps.openBrowser(authUrl);
76660
- } catch (err) {
76661
- error.error(
76662
- `Failed to open browser automatically: ${err instanceof Error ? err.message : String(err)}`
76663
- );
76664
- }
76665
- }
76666
- const callback = await handle.waitForCode();
76667
- const tokenResponse = await fetchImpl(TOKEN_URL, {
76668
- method: "POST",
76669
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
76670
- body: new URLSearchParams({
76671
- client_id: CLIENT_ID,
76672
- client_secret: CLIENT_SECRET,
76673
- code: callback.code,
76674
- grant_type: "authorization_code",
76675
- redirect_uri: redirectUri
76676
- })
76677
- });
76678
- if (!tokenResponse.ok) {
76679
- const body = await tokenResponse.text();
76680
- throw new Error(`Antigravity token exchange failed: ${body}`);
76681
- }
76682
- const tokenData = await tokenResponse.json();
76683
- if (!tokenData.refresh_token) {
76684
- throw new Error("No refresh token received. Please try again.");
76685
- }
76686
- const email = await getUserEmail(fetchImpl, tokenData.access_token);
76687
- const projectId = await discoverProject(
76688
- fetchImpl,
76689
- tokenData.access_token,
76690
- (message) => output2.log(message)
76691
- );
76692
- const now = (deps.now ?? Date.now)();
76693
- return {
76694
- provider: "antigravity",
76695
- accessToken: tokenData.access_token,
76696
- refreshToken: tokenData.refresh_token,
76697
- expiresAt: now + tokenData.expires_in * 1e3 - ACCESS_TOKEN_CLIENT_SKEW_MS2,
76698
- scope: tokenData.scope,
76699
- obtainedAt: now,
76700
- metadata: {
76701
- projectId,
76702
- email
76703
- }
76704
- };
76705
- } finally {
76706
- await handle.close();
76707
- }
76708
- }
76709
- 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;
76710
- var init_antigravity = __esm({
76711
- "packages/cli/oauth/flows/antigravity.ts"() {
76712
- "use strict";
76713
- init_callback_server();
76714
- init_pkce();
76715
- init_token_store();
76716
- decode = (s) => Buffer.from(s, "base64").toString("utf8");
76717
- CLIENT_ID = decode(
76718
- "MTA3MTAwNjA2MDU5MS10bWhzc2luMmgyMWxjcmUyMzV2dG9sb2poNGc0MDNlcC5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbQ=="
76719
- );
76720
- CLIENT_SECRET = decode("R09DU1BYLUs1OEZXUjQ4NkxkTEoxbUxCOHNYQzR6NnFEQWY=");
76721
- CALLBACK_PORT = 51121;
76722
- CALLBACK_PATH = "/oauth-callback";
76723
- SCOPES = [
76724
- "https://www.googleapis.com/auth/cloud-platform",
76725
- "https://www.googleapis.com/auth/userinfo.email",
76726
- "https://www.googleapis.com/auth/userinfo.profile",
76727
- "https://www.googleapis.com/auth/cclog",
76728
- "https://www.googleapis.com/auth/experimentsandconfigs"
76729
- ];
76730
- AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
76731
- TOKEN_URL = "https://oauth2.googleapis.com/token";
76732
- USERINFO_URL = "https://www.googleapis.com/oauth2/v1/userinfo?alt=json";
76733
- CLOUD_CODE_ENDPOINT = "https://cloudcode-pa.googleapis.com";
76734
- TIER_LEGACY = "legacy-tier";
76735
- PROJECT_ONBOARD_MAX_ATTEMPTS = 5;
76736
- PROJECT_ONBOARD_INTERVAL_MS = 2e3;
76737
- ACCESS_TOKEN_CLIENT_SKEW_MS2 = 5 * 60 * 1e3;
76738
- ANTIGRAVITY_LOAD_CODE_ASSIST_METADATA = Object.freeze({
76739
- ideType: "ANTIGRAVITY",
76740
- platform: "PLATFORM_UNSPECIFIED",
76741
- pluginType: "GEMINI"
76742
- });
76743
- }
76744
- });
76745
-
76746
- // packages/cli/oauth/flows/xai.ts
76747
- function validateXAIEndpoint(url, field) {
76748
- let parsed;
76749
- try {
76750
- parsed = new URL(url);
76751
- } catch {
76752
- throw new Error(`Invalid xAI ${field}: ${url}`);
76753
- }
76754
- if (parsed.protocol !== "https:") {
76755
- throw new Error(`Invalid xAI ${field}: ${url}`);
76756
- }
76757
- const host = parsed.hostname.toLowerCase();
76758
- if (!host || host !== "x.ai" && !host.endsWith(".x.ai")) {
76759
- throw new Error(`Invalid xAI ${field}: ${url}`);
76760
- }
76761
- return url;
76762
- }
76763
- async function xaiOAuthDiscovery(fetchImpl, timeoutMs = DISCOVERY_TIMEOUT_MS) {
76764
- let response;
76765
- try {
76766
- response = await fetchImpl(XAI_OAUTH_DISCOVERY_URL, {
76767
- method: "GET",
76768
- headers: { Accept: "application/json" },
76769
- signal: AbortSignal.timeout(timeoutMs)
76770
- });
76771
- } catch (error) {
76772
- throw new Error(
76773
- `xAI OIDC discovery failed: ${error instanceof Error ? error.message : String(error)}`
76774
- );
76775
- }
76776
- if (response.status !== 200) {
76777
- throw new Error(`xAI OIDC discovery returned status ${response.status}.`);
76778
- }
76779
- let payload;
76780
- try {
76781
- payload = await response.json();
76782
- } catch (error) {
76783
- throw new Error(
76784
- `xAI OIDC discovery returned invalid JSON: ${error instanceof Error ? error.message : String(error)}`
76785
- );
76786
- }
76787
- if (!payload || typeof payload !== "object") {
76788
- throw new Error("xAI OIDC discovery response was not a JSON object.");
76789
- }
76790
- const obj = payload;
76791
- const authorizationEndpoint = typeof obj.authorization_endpoint === "string" ? obj.authorization_endpoint.trim() : "";
76792
- const tokenEndpoint = typeof obj.token_endpoint === "string" ? obj.token_endpoint.trim() : "";
76793
- if (!authorizationEndpoint || !tokenEndpoint) {
76794
- throw new Error("xAI OIDC discovery response was missing required endpoints.");
76795
- }
76796
- validateXAIEndpoint(authorizationEndpoint, "authorization_endpoint");
76797
- validateXAIEndpoint(tokenEndpoint, "token_endpoint");
76798
- return {
76799
- authorization_endpoint: authorizationEndpoint,
76800
- token_endpoint: tokenEndpoint
76801
- };
76802
- }
76803
- function buildXAIAuthorizeUrl(opts) {
76804
- const params = new URLSearchParams({
76805
- response_type: "code",
76806
- client_id: XAI_OAUTH_CLIENT_ID,
76807
- redirect_uri: opts.redirectUri,
76808
- scope: XAI_OAUTH_SCOPE,
76809
- code_challenge: opts.codeChallenge,
76810
- code_challenge_method: "S256",
76811
- state: opts.state,
76812
- nonce: opts.nonce,
76813
- plan: "generic",
76814
- referrer: "nolo-cli"
76815
- });
76816
- return `${opts.authorizationEndpoint}?${params.toString()}`;
76817
- }
76818
- function generateState3() {
76819
- const bytes = new Uint8Array(16);
76820
- crypto.getRandomValues(bytes);
76821
- return Array.from(bytes).map((value) => value.toString(16).padStart(2, "0")).join("");
76822
- }
76823
- async function exchangeXAIToken(fetchImpl, code, redirectUri, verifier) {
76824
- const discovery = await xaiOAuthDiscovery(fetchImpl);
76825
- const tokenEndpoint = validateXAIEndpoint(discovery.token_endpoint, "token_endpoint");
76826
- const body = new URLSearchParams({
76827
- grant_type: "authorization_code",
76828
- client_id: XAI_OAUTH_CLIENT_ID,
76829
- code,
76830
- redirect_uri: redirectUri,
76831
- code_verifier: verifier
76832
- });
76833
- const response = await fetchImpl(tokenEndpoint, {
76834
- method: "POST",
76835
- headers: {
76836
- "Content-Type": "application/x-www-form-urlencoded",
76837
- Accept: "application/json"
76838
- },
76839
- body,
76840
- signal: AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS2)
76841
- });
76842
- if (!response.ok) {
76843
- let detail = "";
76844
- try {
76845
- detail = (await response.text()).trim();
76846
- } catch {
76847
- }
76848
- throw new Error(
76849
- `xAI token exchange failed: ${response.status}${detail ? ` ${detail}` : ""}`
76850
- );
76851
- }
76852
- const data = await response.json();
76853
- if (typeof data.access_token !== "string" || !data.access_token) {
76854
- throw new Error("xAI token exchange response missing access_token");
76855
- }
76856
- if (typeof data.refresh_token !== "string" || !data.refresh_token) {
76857
- throw new Error("xAI token exchange response missing refresh_token");
76858
- }
76859
- if (typeof data.expires_in !== "number" || !Number.isFinite(data.expires_in)) {
76860
- throw new Error("xAI token exchange response missing expires_in");
76861
- }
76862
- return {
76863
- accessToken: data.access_token,
76864
- refreshToken: data.refresh_token,
76865
- expiresIn: data.expires_in,
76866
- scope: typeof data.scope === "string" ? data.scope : void 0,
76867
- idToken: typeof data.id_token === "string" ? data.id_token : void 0
76868
- };
76869
- }
76870
- async function runXaiOAuthLogin(deps = {}) {
76871
- const fetchImpl = deps.fetchImpl ?? fetch;
76872
- const output2 = deps.output ?? console;
76873
- const error = deps.error ?? console;
76874
- const redirectUri = `http://${XAI_OAUTH_REDIRECT_HOST}:${XAI_OAUTH_REDIRECT_PORT}${XAI_OAUTH_REDIRECT_PATH}`;
76875
- let handle;
76876
- try {
76877
- handle = await startCallbackServer({
76878
- port: XAI_OAUTH_REDIRECT_PORT,
76879
- hostname: XAI_OAUTH_REDIRECT_HOST,
76880
- timeoutMs: 5 * 6e4
76881
- });
76882
- } catch (err) {
76883
- throw new Error(
76884
- `Failed to start xAI OAuth callback server on ${XAI_OAUTH_REDIRECT_PORT}: ${err instanceof Error ? err.message : String(err)}`
76885
- );
76886
- }
76887
- try {
76888
- const state = generateState3();
76889
- const pkce = await generatePkcePair();
76890
- const nonce = crypto.randomUUID().replace(/-/g, "");
76891
- const discovery = await xaiOAuthDiscovery(fetchImpl);
76892
- const authUrl = buildXAIAuthorizeUrl({
76893
- authorizationEndpoint: discovery.authorization_endpoint,
76894
- redirectUri,
76895
- codeChallenge: pkce.challenge,
76896
- state,
76897
- nonce
76898
- });
76899
- output2.log(
76900
- `Open the following URL in your browser to log in to xAI Grok (SuperGrok):
76901
- ${authUrl}
76902
-
76903
- Docs: ${XAI_OAUTH_DOCS_URL}`
76904
- );
76905
- if (deps.openBrowser) {
76906
- try {
76907
- await deps.openBrowser(authUrl);
76908
- } catch (err) {
76909
- error.error(
76910
- `Failed to open browser automatically: ${err instanceof Error ? err.message : String(err)}`
76911
- );
76912
- }
76913
- }
76914
- const callback = await handle.waitForCode();
76915
- const token = await exchangeXAIToken(
76916
- fetchImpl,
76917
- callback.code,
76918
- redirectUri,
76919
- pkce.verifier
76920
- );
76921
- const now = (deps.now ?? Date.now)();
76922
- const expiresIn = token.expiresIn;
76923
- return {
76924
- provider: "xai",
76925
- accessToken: token.accessToken,
76926
- refreshToken: token.refreshToken,
76927
- expiresAt: now + expiresIn * 1e3 - ACCESS_TOKEN_CLIENT_SKEW_MS3,
76928
- scope: token.scope,
76929
- idToken: token.idToken,
76930
- obtainedAt: now
76931
- };
76932
- } finally {
76933
- await handle.close();
76934
- }
76935
- }
76936
- 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;
76937
- var init_xai = __esm({
76938
- "packages/cli/oauth/flows/xai.ts"() {
76939
- "use strict";
76940
- init_callback_server();
76941
- init_pkce();
76942
- init_token_store();
76943
- XAI_OAUTH_ISSUER = "https://auth.x.ai";
76944
- XAI_OAUTH_DISCOVERY_URL = `${XAI_OAUTH_ISSUER}/.well-known/openid-configuration`;
76945
- XAI_OAUTH_CLIENT_ID = "b1a00492-073a-47ea-816f-4c329264a828";
76946
- XAI_OAUTH_SCOPE = "openid profile email offline_access grok-cli:access api:access";
76947
- XAI_OAUTH_REDIRECT_HOST = "127.0.0.1";
76948
- XAI_OAUTH_REDIRECT_PORT = 56121;
76949
- XAI_OAUTH_REDIRECT_PATH = "/callback";
76950
- XAI_OAUTH_DOCS_URL = "https://hermes-agent.nousresearch.com/docs/guides/xai-grok-oauth";
76951
- ACCESS_TOKEN_CLIENT_SKEW_MS3 = 5 * 60 * 1e3;
76952
- DISCOVERY_TIMEOUT_MS = 15e3;
76953
- TOKEN_REQUEST_TIMEOUT_MS2 = 2e4;
76954
- }
76955
- });
76956
-
76957
77663
  // packages/cli/client/profileConfig.ts
76958
77664
  import { existsSync as existsSync10, mkdirSync as mkdirSync5, readFileSync as readFileSync11, writeFileSync as writeFileSync6 } from "node:fs";
76959
77665
  import { dirname as dirname5, join as join11 } from "node:path";
@@ -77218,7 +77924,7 @@ async function runLoginCommand(args2, deps = {}) {
77218
77924
  serverUrl,
77219
77925
  fetchImpl: deps.fetchImpl ?? fetch,
77220
77926
  openBrowser: deps.openBrowser ?? defaultOpenBrowser,
77221
- sleep: deps.sleep ?? defaultSleep2,
77927
+ sleep: deps.sleep ?? defaultSleep3,
77222
77928
  now: deps.now ?? Date.now,
77223
77929
  output: outputTarget,
77224
77930
  error: errorTarget,
@@ -77286,7 +77992,7 @@ function runLogoutCommand(deps = {}) {
77286
77992
  }
77287
77993
  return 0;
77288
77994
  }
77289
- var LOGIN_HELP_TEXT, LOGOUT_HELP_TEXT, WHOAMI_HELP_TEXT, postJson2, defaultSleep2, defaultOpenBrowser;
77995
+ var LOGIN_HELP_TEXT, LOGOUT_HELP_TEXT, WHOAMI_HELP_TEXT, postJson2, defaultSleep3, defaultOpenBrowser;
77290
77996
  var init_authCommands = __esm({
77291
77997
  "packages/cli/authCommands.ts"() {
77292
77998
  "use strict";
@@ -77326,7 +78032,7 @@ Usage:
77326
78032
  headers: { "Content-Type": "application/json" },
77327
78033
  body: JSON.stringify(body)
77328
78034
  });
77329
- defaultSleep2 = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms));
78035
+ defaultSleep3 = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms));
77330
78036
  defaultOpenBrowser = async (url) => {
77331
78037
  const command2 = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
77332
78038
  const args2 = process.platform === "win32" ? ["/c", "start", "", url] : [url];
@@ -77654,7 +78360,7 @@ ${SYNC_HELP_LINE}
77654
78360
 
77655
78361
  // packages/connector-experimental/heartbeatLoop.ts
77656
78362
  async function runHeartbeatLoop(options) {
77657
- const sleep7 = options.sleep ?? defaultSleep3;
78363
+ const sleep7 = options.sleep ?? defaultSleep4;
77658
78364
  let beats = 0;
77659
78365
  while (!options.signal?.aborted) {
77660
78366
  await options.sendHeartbeat();
@@ -77664,11 +78370,11 @@ async function runHeartbeatLoop(options) {
77664
78370
  await sleep7(options.intervalMs);
77665
78371
  }
77666
78372
  }
77667
- var defaultSleep3;
78373
+ var defaultSleep4;
77668
78374
  var init_heartbeatLoop = __esm({
77669
78375
  "packages/connector-experimental/heartbeatLoop.ts"() {
77670
78376
  "use strict";
77671
- defaultSleep3 = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms));
78377
+ defaultSleep4 = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms));
77672
78378
  }
77673
78379
  });
77674
78380
 
@@ -78281,7 +78987,7 @@ ${text}`);
78281
78987
  return 1;
78282
78988
  }
78283
78989
  const maxAttempts = deps.maxConnectorAttempts ?? Infinity;
78284
- const sleep7 = deps.sleep ?? defaultSleep4;
78990
+ const sleep7 = deps.sleep ?? defaultSleep5;
78285
78991
  const reconnectDelayMs = resolveConnectorReconnectDelayMs(env);
78286
78992
  for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
78287
78993
  if (deps.signal?.aborted) {
@@ -78351,7 +79057,7 @@ ${text}`);
78351
79057
  sendHeartbeat
78352
79058
  });
78353
79059
  }
78354
- var defaultSleep4;
79060
+ var defaultSleep5;
78355
79061
  var init_machineCommands = __esm({
78356
79062
  "packages/cli/machineCommands.ts"() {
78357
79063
  "use strict";
@@ -78366,7 +79072,7 @@ var init_machineCommands = __esm({
78366
79072
  init_machineWsRunDispatch();
78367
79073
  init_machineWsSession();
78368
79074
  init_machineStatusCommands();
78369
- defaultSleep4 = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms));
79075
+ defaultSleep5 = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms));
78370
79076
  }
78371
79077
  });
78372
79078
 
@@ -80283,11 +80989,11 @@ function getAgentInternalCommandEntries() {
80283
80989
  return runAgentReadCommand2(args2, deps);
80284
80990
  }),
80285
80991
  createAgentRunCommand(["agent", "run"], "Run an agent"),
80286
- createEnvCommand(["agent", "ps"], "List active and recent local agent runs", async (_args, deps) => {
80992
+ createEnvCommand(["agent", "ps"], "List active and recent local agent runs (--json for machine-readable output)", async (_args, deps) => {
80287
80993
  const { runAgentPsCommand: runAgentPsCommand2 } = await Promise.resolve().then(() => (init_agentRunControl(), agentRunControl_exports));
80288
80994
  return runAgentPsCommand2(_args, { ...deps, output: process.stdout });
80289
80995
  }),
80290
- createEnvCommand(["agent", "status"], "Show status of a local agent run", async (args2, deps) => {
80996
+ createEnvCommand(["agent", "status"], "Show status of a local agent run (--json, --watch, --interval-ms N)", async (args2, deps) => {
80291
80997
  const { runAgentStatusCommand: runAgentStatusCommand2 } = await Promise.resolve().then(() => (init_agentRunControl(), agentRunControl_exports));
80292
80998
  return runAgentStatusCommand2(args2, { ...deps, output: process.stdout });
80293
80999
  }),