talon-agent 5.3.0 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/cli/setup.ts CHANGED
@@ -6,6 +6,8 @@
6
6
  import * as p from "@clack/prompts";
7
7
  import pc from "picocolors";
8
8
  import { printBanner, loadConfig, saveConfig, type Config } from "./config.js";
9
+ import { binaryOnPath } from "../util/binary-on-path.js";
10
+ import { detectAgyAuth } from "../backend/agy/auth.js";
9
11
 
10
12
  /** Strip spaces, "+", brackets and dashes from a phone number. */
11
13
  const bareDigits = (raw: string) => raw.replace(/[\s+()-]/g, "");
@@ -393,6 +395,10 @@ async function askBackend(config: Config): Promise<Config["backend"]> {
393
395
  value: "codex",
394
396
  label: `Codex ${pc.dim("— OpenAI Codex CLI (@openai/codex)")}`,
395
397
  },
398
+ {
399
+ value: "agy",
400
+ label: `Antigravity ${pc.dim("— Google Antigravity CLI (agy, subscription OAuth)")}`,
401
+ },
396
402
  {
397
403
  value: "openai-agents",
398
404
  label: `OpenAI Agents ${pc.dim("— @openai/agents (OpenAI or any OpenAI-compatible endpoint)")}`,
@@ -405,6 +411,7 @@ async function askBackend(config: Config): Promise<Config["backend"]> {
405
411
  type BackendAnswers = Pick<
406
412
  SetupAnswers,
407
413
  | "claudeBinary"
414
+ | "agyBinary"
408
415
  | "codexApiKey"
409
416
  | "openaiApiKey"
410
417
  | "openaiBaseUrl"
@@ -434,6 +441,44 @@ async function askCodexBackend(config: Config): Promise<BackendAnswers> {
434
441
  return { codexApiKey: trimmedOrUndefined(codexApiKey) };
435
442
  }
436
443
 
444
+ /**
445
+ * Antigravity has no API key to collect — it authenticates through a
446
+ * consumer Google OAuth flow run once interactively, cached under
447
+ * `~/.gemini/antigravity-cli/`. All the wizard can usefully do is
448
+ * point at the binary and say where the login happens.
449
+ */
450
+ async function askAgyBackend(config: Config): Promise<BackendAnswers> {
451
+ const binary = await askOrExit(
452
+ p.text({
453
+ message: "Antigravity CLI binary path",
454
+ placeholder: "leave empty for default (agy on PATH)",
455
+ initialValue: config.agyBinary || "",
456
+ }),
457
+ );
458
+ const resolved = trimmedOrUndefined(binary);
459
+ const probe = resolved || "agy";
460
+ const installed = binaryOnPath(probe);
461
+ if (!installed) {
462
+ p.log.warn(
463
+ `${pc.yellow("!")} \`${probe}\` not found — install the Antigravity CLI ` +
464
+ `and make sure it is on PATH before starting Talon.`,
465
+ );
466
+ }
467
+ const auth = detectAgyAuth();
468
+ if (!auth.present) {
469
+ p.log.warn(
470
+ `${pc.yellow("!")} No cached Antigravity credentials. Run ${pc.cyan("agy")} ` +
471
+ `once on this host and complete the Google sign-in; headless runs ` +
472
+ `then reuse the cache. There is no API key for this backend.`,
473
+ );
474
+ } else {
475
+ p.log.success(
476
+ `Antigravity credentials found (${auth.method ?? "oauth"}) at ${auth.path}`,
477
+ );
478
+ }
479
+ return { agyBinary: resolved };
480
+ }
481
+
437
482
  async function askOpenAiAgentsBackend(config: Config): Promise<BackendAnswers> {
438
483
  const openaiApiKey = trimmedOrUndefined(
439
484
  await askOrExit(
@@ -494,6 +539,8 @@ async function askBackendCredentials(
494
539
  return askClaudeBackend(config);
495
540
  case "codex":
496
541
  return askCodexBackend(config);
542
+ case "agy":
543
+ return askAgyBackend(config);
497
544
  case "openai-agents":
498
545
  return askOpenAiAgentsBackend(config);
499
546
  default:
@@ -553,6 +600,7 @@ export type SetupAnswers = {
553
600
  backend: Config["backend"];
554
601
  botToken?: string;
555
602
  claudeBinary?: string;
603
+ agyBinary?: string;
556
604
  codexApiKey?: string;
557
605
  openaiApiKey?: string;
558
606
  openaiBaseUrl?: string;
@@ -612,6 +660,7 @@ export function buildSetupConfig(
612
660
  codexApiKey: ownsCredential("codex")
613
661
  ? answers.codexApiKey
614
662
  : existing.codexApiKey,
663
+ agyBinary: ownsCredential("agy") ? answers.agyBinary : existing.agyBinary,
615
664
  openaiApiKey: ownsCredential("openai-agents")
616
665
  ? answers.openaiApiKey
617
666
  : existing.openaiApiKey,
@@ -28,6 +28,7 @@ import type { ReasoningEffortLevel } from "../types.js";
28
28
  * lockstep.
29
29
  */
30
30
  export const BACKEND_IDS = [
31
+ "agy",
31
32
  "claude",
32
33
  "codex",
33
34
  "kilo",
@@ -360,6 +360,7 @@ const configSchema = z.object({
360
360
  * unset, the codex-sdk resolves `codex` from its package / PATH.
361
361
  */
362
362
  codexBinary: z.string().optional(),
363
+ agyBinary: z.string().optional(),
363
364
  model: z.string().default("default"),
364
365
  /**
365
366
  * Per-backend default model overrides. Keyed by backend id