@estebanforge/pi-ask-antigravity 1.1.0 → 1.2.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.
@@ -54,6 +54,9 @@ const GLOBAL_CONFIG_PATH = path.join(os.homedir(), ".pi", "agent", "ask-antigrav
54
54
 
55
55
  const DEFAULT_MODEL = "flash";
56
56
  const DEFAULT_THINKING = "medium";
57
+ // Default on: without --dangerously-skip-permissions, any run_command hangs in
58
+ // non-interactive -p mode (accept-edits auto-approves edits, NOT commands).
59
+ const DEFAULT_SKIP_PERMISSIONS = true;
57
60
 
58
61
  // Per-family fallback tier when none is specified and no config default.
59
62
  // Flash defaults to medium (per spec); Pro only ships Low/High, so "latest
@@ -146,6 +149,9 @@ interface ModelEntry {
146
149
  interface Config {
147
150
  defaultModel: string;
148
151
  defaultThinking: ThinkingTier;
152
+ /** Pass --dangerously-skip-permissions so commands don't hang on an
153
+ * unanswerable y/n prompt in non-interactive -p mode. Default true. */
154
+ skipPermissions: boolean;
149
155
  }
150
156
 
151
157
  // --- Version helpers -------------------------------------------------------
@@ -188,9 +194,16 @@ function loadConfig(): Config {
188
194
  const thinking: ThinkingTier =
189
195
  thinkingRaw === "low" || thinkingRaw === "high" ? thinkingRaw : "medium";
190
196
 
197
+ const envPerm = process.env.AGY_SKIP_PERMISSIONS;
198
+ const skipPermissions =
199
+ envPerm !== undefined
200
+ ? envPerm === "1" || envPerm.toLowerCase() === "true"
201
+ : merged.skipPermissions === false ? false : DEFAULT_SKIP_PERMISSIONS;
202
+
191
203
  return {
192
204
  defaultModel: String(merged.defaultModel ?? DEFAULT_MODEL).trim() || DEFAULT_MODEL,
193
205
  defaultThinking: thinking,
206
+ skipPermissions,
194
207
  };
195
208
  }
196
209
 
@@ -367,6 +380,52 @@ function resolveAgy(): string {
367
380
  return process.env.AGY_BIN || "agy";
368
381
  }
369
382
 
383
+ // Defer to pi-antigravity-bridge when it is installed: the bridge provides BOTH
384
+ // the streaming antigravity provider AND the AskAntigravity tool (same shape as
385
+ // pi-claude-bridge). Registering the tool here too would create a duplicate.
386
+ //
387
+ // Detection does NOT rely on module resolution: pi loads each package with a
388
+ // separate module root (docs/packages.md), so require.resolve from here never
389
+ // reaches a sibling package. Instead we check:
390
+ // 1. An in-process Symbol.for flag the bridge sets at its load (fast path
391
+ // when the bridge loaded earlier this session).
392
+ // 2. The bridge's package.json at pi's documented install locations
393
+ // (~/.pi/agent/npm|git/... and project .pi/npm|git/...).
394
+ //
395
+ // Coverage: (2) is order-independent for npm/git installs - installation is a
396
+ // fact on disk. For LOCAL/source installs (`pi install <path>`) the package
397
+ // lives at its original checkout, not under .pi/npm|git/, so (2) sees nothing;
398
+ // there only (1) helps, and only if the bridge loads first. Recommendation for
399
+ // dev with both repos checked out side-by-side: install the bridge first so it
400
+ // is earlier in settings.json (pi loads extensions in that order). If the
401
+ // clash still occurs, both tools are functionally identical, so the only
402
+ // symptom is a duplicate-name TUI warning - not broken behavior.
403
+ const BRIDGE_FLAG = Symbol.for("pi-antigravity-bridge:active");
404
+
405
+ function bridgeInstallPaths(): string[] {
406
+ const npmPkg = path.join("@estebanforge", "pi-antigravity-bridge", "package.json");
407
+ const gitPkg = path.join("EstebanForge", "pi-antigravity-bridge", "package.json");
408
+ const home = os.homedir();
409
+ const cwd = process.cwd();
410
+ return [
411
+ path.join(home, ".pi", "agent", "npm", "node_modules", npmPkg),
412
+ path.join(cwd, ".pi", "npm", "node_modules", npmPkg),
413
+ path.join(home, ".pi", "agent", "git", "github.com", gitPkg),
414
+ path.join(cwd, ".pi", "git", "github.com", gitPkg),
415
+ ];
416
+ }
417
+
418
+ const isBridgeInstalled = (): boolean => {
419
+ if ((globalThis as Record<symbol, unknown>)[BRIDGE_FLAG]) return true;
420
+ return bridgeInstallPaths().some((p) => {
421
+ try {
422
+ return fs.existsSync(p);
423
+ } catch {
424
+ return false;
425
+ }
426
+ });
427
+ };
428
+
370
429
  const sleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));
371
430
 
372
431
  /** Query `agy models`. Returns [] on any failure (non-fatal). */
@@ -466,6 +525,12 @@ interface AgyDetails {
466
525
  }
467
526
 
468
527
  export default async function (pi: ExtensionAPI) {
528
+ // If pi-antigravity-bridge is installed, it owns the AskAntigravity tool
529
+ // (and the provider). Stay silent and register nothing to avoid a
530
+ // duplicate-tool clash. Without the bridge, this extension behaves as
531
+ // before (standalone tool).
532
+ if (isBridgeInstalled()) return;
533
+
469
534
  const binary = resolveAgy();
470
535
  // Discovered once at load; frozen for the session. Run /reload after an
471
536
  // `agy update` to refresh. Failure is non-fatal: resolveModel falls back
@@ -494,6 +559,7 @@ export default async function (pi: ExtensionAPI) {
494
559
  `AskAntigravity config`,
495
560
  ` defaultModel: ${config.defaultModel}`,
496
561
  ` defaultThinking: ${config.defaultThinking}`,
562
+ ` permissions: ${config.skipPermissions ? "auto-approved" : "prompt"}`,
497
563
  ` resolved: ${resolveModel(config.defaultModel, discovered, config.defaultThinking) ?? "(agy default)"}`,
498
564
  ``,
499
565
  `Edit: ~/.pi/agent/ask-antigravity.json`,
@@ -527,6 +593,14 @@ export default async function (pi: ExtensionAPI) {
527
593
  currentValue: config.defaultThinking,
528
594
  values: THINKING_OPTIONS,
529
595
  },
596
+ {
597
+ id: "permissions",
598
+ label: "Permissions",
599
+ description:
600
+ "auto-approved: --dangerously-skip-permissions (required so run_command doesn't hang in -p mode). prompt: agy asks y/n (hangs non-interactively).",
601
+ currentValue: config.skipPermissions ? "auto-approved" : "prompt",
602
+ values: ["auto-approved", "prompt"],
603
+ },
530
604
  ];
531
605
 
532
606
  const pending: Partial<Config> = {};
@@ -548,6 +622,8 @@ export default async function (pi: ExtensionAPI) {
548
622
  pending.defaultModel = alias;
549
623
  } else if (id === "defaultThinking") {
550
624
  pending.defaultThinking = newValue as ThinkingTier;
625
+ } else if (id === "permissions") {
626
+ pending.skipPermissions = newValue === "auto-approved";
551
627
  }
552
628
  },
553
629
  () => done(undefined),
@@ -742,6 +818,10 @@ export default async function (pi: ExtensionAPI) {
742
818
  if (extra.length) args.push(...extra);
743
819
  if (resolved) args.push("--model", resolved);
744
820
  args.push("--mode", mode);
821
+ // accept-edits auto-approves file edits but NOT shell commands, so a
822
+ // run_command would hang on an unanswerable y/n prompt in non-interactive
823
+ // -p mode. Honor the shared permissions setting (same knob as the bridge).
824
+ if (config.skipPermissions) args.push("--dangerously-skip-permissions");
745
825
  if (isContinuation) args.push("--conversation", rawConvId as string);
746
826
  args.push("--print-timeout", `${timeoutMin}m`);
747
827
  args.push("-p", finalPrompt);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@estebanforge/pi-ask-antigravity",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Pi tool that delegates a self-contained sub-task to Google Antigravity's agy CLI (the CLI for Gemini). Friendly model aliases (flash/pro/gemini), configurable default model + thinking, and the AskAntigravity delegation tool.",
5
5
  "keywords": [
6
6
  "pi-package",