@estebanforge/pi-ask-antigravity 1.3.1 → 1.3.4

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,7 +2,28 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
- ## [Unreleased]
5
+ ## [1.3.4] - 2026-11-10
6
+
7
+ ### Added
8
+
9
+ - **The AskAntigravity defaults dialog reports blocked-on-user-input while open.** Pi 1.5.1 lets overlay dialogs declare a blocked program status (OSC 7501); the dialog now passes it, so terminal automation watching the session sees pi waiting on input instead of idle. Pi dependency floor moved to ^1.5.1.
10
+
11
+ ### Changed
12
+ - The finishing-window stop guard now reads the run's registry status instead of a wall-clock-aligned side set: same refusal behavior, and the test awaits the lifecycle transition instead of a fixed 250ms delay (flaked under full-suite load). Shared dependency floor moves to ^0.1.5 (`markFinishing`) once shared publishes.
13
+
14
+ ### Fixed
15
+ - Windows: `agy models` discovery now resolves the binary like the shared runner does (native `.exe`/`.com` on `PATH`, explicit `AGY_BIN` paths honored, npm shims reported as unavailable instead of a cryptic spawn failure), and every run kills its process tree via `taskkill` instead of POSIX group signals that never fire on Windows.
16
+
17
+ ## [1.3.3] - 2026-11-02
18
+
19
+ ### Fixed
20
+ - The tool result expand hint now comes from the render context pi injects (`context.keyHint`) instead of the package import. pi 1.5 blinds an imported `keyHint` to the host keybindings (app.* ids format as ""), so the hint rendered as "to expand" with no key. Peer floor moves to `^1.5.0` accordingly.
21
+
22
+ ## [1.3.2] - 2026-10-27
23
+
24
+ ### Fixed
25
+
26
+ - **`/agy-stop` no longer discards an answer that already finished computing.** Between the agy process closing and the run settling (conversation discovery + classification, up to ~500ms), a stop settled the run failed and silently dropped the computed answer. The stop handler now consults a finishing guard (the new opt-in `guard` option on pi-ask-shared's `createStopHandler`, dependency floor raised to ^0.1.3) and refuses with "already finished; its result is being delivered" while that window is open; the wake then delivers normally.
6
27
 
7
28
  ## [1.3.1] - 2026-10-21
8
29
 
@@ -41,7 +62,6 @@ All notable changes to this project will be documented in this file.
41
62
 
42
63
  - **Background runs (`background`, opt-in, default blocking).** Detached runs with the shared wake contract: `runId` at once, the answer arrives later as a conversation message with the resume handle (when agy reports one; discovery misses say so) under an UNTRUSTED banner. `/agy-stop [runId]` kills a run. One run per conversation at a time across blocking and background (per-handle lock). Refused in print/json mode; session replacement kills in-flight runs and loses their results; the staged context file and plan-mode reviewer dir are cleaned on every exit path including session shutdown.
43
64
 
44
-
45
65
  ### Fixed
46
66
 
47
67
  - **Plan runs are no longer auto-approved and no longer claim enforcement.** The CLI does not gate writes under plan mode ([#1181](https://github.com/google-antigravity/antigravity-cli/issues/1181)): the previously documented "write attempts fail at plan approval" behavior never held, and plan runs carrying the skip-permissions flag (whenever the restricted agent staged) were write-capable. Plan runs now never receive the flag (including via `AGY_EXTRA_ARGS`, filtered by prefix), the restricted agent is documented as a damper, and the tool description, param description, and README no longer call plan review-only or enforced.
@@ -37,12 +37,11 @@ import {
37
37
  type AgentToolResult,
38
38
  buildSessionContext,
39
39
  getAgentDir,
40
- keyHint,
41
40
  type ExtensionAPI,
42
41
  } from "@earendil-works/pi-coding-agent";
43
42
 
44
43
  import { Text } from "@earendil-works/pi-tui";
45
- import { DIALOG_OPTIONS, DialogMenu, type DialogRow } from "@estebanforge/pi-tui-dialogs";
44
+ import { DIALOG_OPTIONS, DialogMenu, dialogBlocked, type DialogRow } from "@estebanforge/pi-tui-dialogs";
46
45
  import { contentText } from "@earendil-works/pi-ai";
47
46
  import { Type } from "typebox";
48
47
  import {
@@ -66,6 +65,7 @@ import {
66
65
  newConversationId,
67
66
  parseModelLine,
68
67
  resolveAgyModel,
68
+ resolveSpawnTarget,
69
69
  RunSpawnError,
70
70
  runProcess,
71
71
  saveLayeredConfig,
@@ -351,9 +351,11 @@ const sleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));
351
351
 
352
352
  /** Query `agy models`. Returns [] on any failure (non-fatal). */
353
353
  async function discoverModels(binary: string): Promise<ModelEntry[]> {
354
+ const target = resolveSpawnTarget(binary);
355
+ if (target.kind === "unavailable") return [];
354
356
  try {
355
357
  const text = await new Promise<string>((resolve, reject) => {
356
- const proc = spawn(binary, ["models"], {
358
+ const proc = spawn(target.file, ["models"], {
357
359
  stdio: ["ignore", "pipe", "ignore"],
358
360
  shell: false,
359
361
  });
@@ -513,6 +515,8 @@ interface ProcessRunOptions {
513
515
  /** Background only: hands over the tree-kill switch plus the live child
514
516
  * handle (pid for the FD-disambiguation poll) as soon as the child exists. */
515
517
  onSpawn?: (kill: () => void, proc: ChildProcess) => void;
518
+ /** Background only: the child closed; discovery/classification still running. Arms the stop handler's finishing guard. */
519
+ onClose?: () => void;
516
520
  }
517
521
 
518
522
  interface ProcessRunOutcome {
@@ -535,7 +539,7 @@ interface AskToolResult {
535
539
  * resolves when the process tree closes.
536
540
  */
537
541
  async function runAgyProcess(opts: ProcessRunOptions): Promise<ProcessRunOutcome> {
538
- const { binary, args, workdir, timeoutMin, startAt, details, isContinuation, snapshot, signal, onPartial, onSpawn } = opts;
542
+ const { binary, args, workdir, timeoutMin, startAt, details, isContinuation, snapshot, signal, onPartial, onSpawn, onClose } = opts;
539
543
  let out = "";
540
544
 
541
545
  const statusInterval = onPartial
@@ -596,6 +600,9 @@ async function runAgyProcess(opts: ProcessRunOptions): Promise<ProcessRunOutcome
596
600
  });
597
601
 
598
602
  if (statusInterval) clearInterval(statusInterval);
603
+ // runProcess resolves only on stream close: the child is gone, output
604
+ // drained; discovery/classification still runs below.
605
+ onClose?.();
599
606
 
600
607
  // Let the during-run bind poll finish (it bails immediately once agy
601
608
  // has exited, so this rarely blocks).
@@ -687,7 +694,11 @@ function shapeFinalText(details: AgyDetails, outcome: ProcessRunOutcome, timeout
687
694
  return text + footer;
688
695
  }
689
696
 
690
- export default async function (pi: ExtensionAPI) {
697
+ export default async function (
698
+ pi: ExtensionAPI,
699
+ // Injectable so tests can await lifecycle phases; production uses the default.
700
+ registry: BackgroundRunRegistry = new BackgroundRunRegistry({ toolName: "ask-antigravity" }),
701
+ ) {
691
702
  // If pi-antigravity-bridge is installed, it owns the AskAntigravity tool
692
703
  // (and the provider). Stay silent and register nothing to avoid a
693
704
  // duplicate-tool clash. Without the bridge, this extension behaves as
@@ -714,7 +725,6 @@ export default async function (pi: ExtensionAPI) {
714
725
  // Pi wipes module state on /new, /resume, /fork and /reload: an in-flight
715
726
  // background run is killed and its result is never delivered. Accepted
716
727
  // trade-off, documented in the README.
717
- const registry = new BackgroundRunRegistry({ toolName: "ask-antigravity" });
718
728
  const kills = new Map<string, () => void>();
719
729
  // Staged-artifact cleanup (contextFile + reviewer agent dir), keyed by run:
720
730
  // the session_shutdown backstop runs these when a hard exit would skip the
@@ -737,6 +747,14 @@ export default async function (pi: ExtensionAPI) {
737
747
  elapsedS: Math.round((Date.now() - run.startedAt) / 1000),
738
748
  error: "stopped via /agy-stop",
739
749
  }),
750
+ // The guard keeps /agy-stop from discarding an answer that already
751
+ // finished computing and is riding discovery to its wake. `finishing`
752
+ // lives in the registry (status set at child close), so the window is
753
+ // observable instead of wall-clock aligned.
754
+ guard: (run) =>
755
+ registry.get(run.runId)?.status === "finishing"
756
+ ? `Run ${run.runId} already finished; its result is being delivered.`
757
+ : null,
740
758
  });
741
759
  pi.on("session_shutdown", () => {
742
760
  // Latch first so close-handler wakes stay silent, then kill children,
@@ -846,7 +864,7 @@ export default async function (pi: ExtensionAPI) {
846
864
  },
847
865
  };
848
866
  },
849
- DIALOG_OPTIONS,
867
+ { ...DIALOG_OPTIONS, blocked: dialogBlocked("AskAntigravity defaults") },
850
868
  );
851
869
 
852
870
  if (Object.keys(pending).length === 0) return;
@@ -981,7 +999,7 @@ export default async function (pi: ExtensionAPI) {
981
999
  if (args.includeContext) tags.push("context=full");
982
1000
  if (args.background) tags.push("bg");
983
1001
 
984
- let text = theme.fg("mdLink", theme.bold("AskAntigravity "));
1002
+ let text = theme.fg("success", theme.bold("AskAntigravity "));
985
1003
  text += `${theme.fg("accent", `[${tags.join(", ")}]`)} `;
986
1004
 
987
1005
  const prompt = String(args.prompt ?? "");
@@ -993,11 +1011,11 @@ export default async function (pi: ExtensionAPI) {
993
1011
  }
994
1012
  return new Text(text, 0, 0);
995
1013
  },
996
- renderResult(result, { expanded, isPartial }, theme) {
1014
+ renderResult(result, { expanded, isPartial }, theme, context) {
997
1015
  const d = result.details as AgyDetails | undefined;
998
1016
  if (isPartial) {
999
1017
  const status = result.content[0]?.type === "text" ? result.content[0].text : "working...";
1000
- return new Text(theme.fg("mdLink", "◉ AskAntigravity ") + theme.fg("muted", status), 0, 0);
1018
+ return new Text(theme.fg("success", "◉ AskAntigravity ") + theme.fg("muted", status), 0, 0);
1001
1019
  }
1002
1020
 
1003
1021
  const body = result.content[0]?.type === "text" ? result.content[0].text : "";
@@ -1006,7 +1024,7 @@ export default async function (pi: ExtensionAPI) {
1006
1024
 
1007
1025
  let text = errored
1008
1026
  ? theme.fg("error", "✗ AskAntigravity error")
1009
- : theme.fg("mdLink", "✓ AskAntigravity");
1027
+ : theme.fg("success", "✓ AskAntigravity");
1010
1028
 
1011
1029
  const rTags: string[] = [];
1012
1030
  if (d?.resolvedModel || d?.model) rTags.push(`model=${d?.resolvedModel ?? d?.model}`);
@@ -1023,7 +1041,7 @@ export default async function (pi: ExtensionAPI) {
1023
1041
  const lines = truncated.split("\n").slice(0, PREVIEW_MAX_LINES);
1024
1042
  if (lines.length) text += `\n${theme.fg("toolOutput", lines.join("\n"))}`;
1025
1043
  if (body.length > PREVIEW_MAX_CHARS || body.split("\n").length > PREVIEW_MAX_LINES) {
1026
- text += `\n${theme.fg("dim", `… (${keyHint("app.tools.expand", "to expand")})`)}`;
1044
+ text += `\n${theme.fg("dim", `… (${context.keyHint("app.tools.expand", "to expand")})`)}`;
1027
1045
  }
1028
1046
  }
1029
1047
  return new Text(text, 0, 0);
@@ -1457,6 +1475,7 @@ export default async function (pi: ExtensionAPI) {
1457
1475
  onSpawn: (kill) => {
1458
1476
  kills.set(runId, kill);
1459
1477
  },
1478
+ onClose: () => registry.markFinishing(runId),
1460
1479
  })
1461
1480
  .then((outcome) => {
1462
1481
  kills.delete(runId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@estebanforge/pi-ask-antigravity",
3
- "version": "1.3.1",
3
+ "version": "1.3.4",
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",
@@ -28,8 +28,8 @@
28
28
  },
29
29
  "type": "module",
30
30
  "dependencies": {
31
- "@estebanforge/pi-ask-shared": "^0.1.2",
32
- "@estebanforge/pi-tui-dialogs": "^0.1.1"
31
+ "@estebanforge/pi-ask-shared": "^0.1.5",
32
+ "@estebanforge/pi-tui-dialogs": "^0.1.3"
33
33
  },
34
34
  "files": [
35
35
  "extensions",
@@ -43,7 +43,7 @@
43
43
  ]
44
44
  },
45
45
  "peerDependencies": {
46
- "@earendil-works/pi-coding-agent": "^1.0.0"
46
+ "@earendil-works/pi-coding-agent": "^1.5.1"
47
47
  },
48
48
  "peerDependenciesMeta": {
49
49
  "@earendil-works/pi-coding-agent": {