@estebanforge/pi-antigravity-bridge 1.7.4 → 1.7.5

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/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [1.7.5] - 2026-09-25
6
+
7
+ ### Fixed
8
+
9
+ - **Exit 0 with no output is a failure, not a silent success.** A headless `agy -p` run can end cleanly with nothing on stdout when a delegated tool call hits a permission gate the headless run cannot prompt for. The plan-mode fix (withholding the skip flag in plan) makes the command gate the common case: the call is auto-denied, the reason goes only to stderr, agy exits 0, and the execute path fell through to success, returning just the conversation footer. The delegating model read that as "returned only a conversationId, zero output, no error" (silent-failure handoff, 2026-09-25). An empty answer now returns a loud failure note carrying the redacted stderr plus the remedy (allow-list the command under `permissions.allow` in the CLI settings, or rerun outside plan mode), the ask-end log marks the run warn with an `empty` flag so error-only default logging records what the chat saw, and a new `details.empty` marker flips the TUI result row to its error glyph instead of a green checkmark. Three new tests pin both stderr shapes and the glyph flip through the fake-binary stub.
10
+
5
11
  ## [1.7.4] - 2026-09-25
6
12
 
7
13
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@estebanforge/pi-antigravity-bridge",
3
- "version": "1.7.4",
3
+ "version": "1.7.5",
4
4
  "description": "Gemini provider for Pi on the Antigravity ACP server (official Google ACP) or the stream-json agy CLI. antigravity/* models in Pi's /model picker, no-patch MCP bridge: agy runs Pi's tools. ToS safe to use.",
5
5
  "keywords": [
6
6
  "pi-package",
package/src/ask-tool.ts CHANGED
@@ -390,7 +390,8 @@ export async function registerAskAntigravityTool(
390
390
  }
391
391
 
392
392
  const body = result.content[0]?.type === "text" ? result.content[0].text : "";
393
- const errored = d?.exitCode !== 0 || !!d?.aborted || !!d?.timedOut;
393
+ const errored =
394
+ d?.exitCode !== 0 || !!d?.aborted || !!d?.timedOut || !!d?.empty;
394
395
 
395
396
  let text = errored
396
397
  ? theme.fg("error", "✗ AskAntigravity error")
@@ -710,10 +711,11 @@ export async function registerAskAntigravityTool(
710
711
  details.aborted = outcome.aborted;
711
712
  details.timedOut = outcome.timedOut;
712
713
  details.durationMs = Date.now() - start;
714
+ const text = out.trim();
713
715
  log?.(
714
716
  "ask-end",
715
- { exitCode: outcome.exitCode, aborted: outcome.aborted, timedOut: outcome.timedOut, durationMs: details.durationMs, conversationId: details.conversationId },
716
- outcome.exitCode !== 0 || outcome.aborted || outcome.timedOut ? "warn" : "info",
717
+ { exitCode: outcome.exitCode, aborted: outcome.aborted, timedOut: outcome.timedOut, empty: !text, durationMs: details.durationMs, conversationId: details.conversationId },
718
+ outcome.exitCode !== 0 || outcome.aborted || outcome.timedOut || !text ? "warn" : "info",
717
719
  );
718
720
 
719
721
  if (!isContinuation && !details.conversationId && snapshot) {
@@ -727,8 +729,6 @@ export async function registerAskAntigravityTool(
727
729
  }
728
730
  }
729
731
 
730
- const text = out.trim();
731
-
732
732
  if (outcome.aborted) {
733
733
  return {
734
734
  content: [
@@ -763,6 +763,25 @@ export async function registerAskAntigravityTool(
763
763
  };
764
764
  }
765
765
 
766
+ // Exit 0 with nothing on stdout is still a failure for the
767
+ // delegator: headless agy auto-denies a permission-gated tool call
768
+ // (e.g. the command gate in plan mode), prints the reason only to
769
+ // stderr, and ends cleanly. Falling through to the success path here
770
+ // returned just the conversation footer, which read as an empty
771
+ // success (silent-failure bug found 2026-09-25).
772
+ if (!text) {
773
+ details.empty = true;
774
+ const stderr = redactText(details.stderr.trim());
775
+ const note = [
776
+ "agy exited cleanly but produced no output.",
777
+ stderr ? `stderr: ${stderr}` : null,
778
+ "Common cause: a tool call needed a permission that headless mode cannot prompt for (typically the command gate in plan mode), so it was auto-denied. Allow-list it under permissions.allow in ~/.gemini/antigravity-cli/settings.json, or rerun outside plan mode with skipPermissions.",
779
+ ]
780
+ .filter(Boolean)
781
+ .join(" ");
782
+ return { content: [{ type: "text", text: note }], details };
783
+ }
784
+
766
785
  onUpdate?.({ content: [{ type: "text", text: "" }], details: { ...details } });
767
786
  const footer = details.conversationId
768
787
  ? `\n\n[agy conversationId: ${details.conversationId} - pass as conversationId to continue this conversation]`
@@ -866,6 +885,9 @@ interface AgyDetails {
866
885
  exitCode: number;
867
886
  aborted: boolean;
868
887
  timedOut: boolean;
888
+ // Exit 0 with no answer on stdout (the empty-output failure branch).
889
+ // renderResult flips to the error glyph on it.
890
+ empty?: boolean;
869
891
  durationMs: number;
870
892
  stderr: string;
871
893
  }