@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 +22 -2
- package/extensions/index.ts +31 -12
- package/package.json +4 -4
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
|
-
## [
|
|
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.
|
package/extensions/index.ts
CHANGED
|
@@ -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(
|
|
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 (
|
|
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("
|
|
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("
|
|
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("
|
|
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.
|
|
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.
|
|
32
|
-
"@estebanforge/pi-tui-dialogs": "^0.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.
|
|
46
|
+
"@earendil-works/pi-coding-agent": "^1.5.1"
|
|
47
47
|
},
|
|
48
48
|
"peerDependenciesMeta": {
|
|
49
49
|
"@earendil-works/pi-coding-agent": {
|