@estebanforge/pi-ask-antigravity 1.2.4 → 1.2.6

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 ADDED
@@ -0,0 +1,220 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [1.2.5] - 2026-09-18
6
+
7
+ ### Added
8
+
9
+ - **`thinking` / `effort` params on AskAntigravity (synonyms).** Port of the pi-antigravity-bridge fix: delegation calls had no direct tier knob (only tier sugar inside `model`, "flash high"), so a caller told "peer review on high thinking" fell through to the configured default with no signal anything was dropped. `thinking` takes pi vocabulary (minimal|low|medium|high|xhigh|max, clamped to agy's low|medium|high; unknown values fall back to low) and `effort` is the same knob under agy's own name. Explicit level beats a tier embedded in `model` and the config default; different values on both errors; fixed-thinking families ignore it because agy rejects `--effort` for them.
10
+
11
+ ## [1.2.4] - 2026-08-13
12
+
13
+ ### Added
14
+
15
+ - **Model, thinking tier, and mode shown next to the tool name.** While a
16
+ delegation runs, the TUI now renders
17
+ `AskAntigravity [model=gemini-3.6-flash, thinking=high]` with a prompt
18
+ preview, plus a tidy result row (`✓ AskAntigravity 12.3s`) with an
19
+ expandable body. Built on pi's `renderCall`/`renderResult` hooks; the
20
+ values shown are the resolved config defaults (model alias + tier), not
21
+ just the args the caller passed. `AgyDetails` gained a `thinking` field.
22
+ - **Opt-in full-context delegation (`includeContext`).** New boolean param
23
+ (default `false`, isolated one-shot unchanged). When `true`, the current pi
24
+ conversation is exported as resolved markdown to
25
+ `~/.pi/extensions-data/estebanforge/pi-ask-antigravity/` and the prompt
26
+ tells agy to read it first. The run passes `--add-dir` for that folder so
27
+ the sandbox can read it; the temp file is removed after the run.
28
+
29
+ ## [1.2.3] - 2026-08-10
30
+
31
+ ### Fixed
32
+
33
+ - **Model parsing now handles agy's real two-column output.** `agy models`
34
+ prints `<slug> <display label>` per line, and `--model` accepts only the
35
+ slug. `parseModelLine` swallowed the whole line and the static
36
+ `sonnet`/`opus`/`gpt-oss` overlay used display labels, so `--model` was
37
+ rejected. It now splits column 1; the overlay uses real slugs
38
+ (`claude-sonnet-4-6`, `claude-opus-4-6-thinking`, `gpt-oss-120b-medium`);
39
+ and `resolveModel` returns a `{model, effort?}` shape that sends
40
+ Gemini-family bases' tier to `--effort` while fixed-thinking families keep
41
+ the exact slug with no `--effort` (agy rejects it for them).
42
+ `parseModelLine`/`mergeCatalog`/`resolveModel` are now exported, with
43
+ two-column parser tests on the verified live `agy models` fixture.
44
+
45
+ ## [1.2.1] - 2026-08-06
46
+
47
+ ### Changed
48
+ - **Dependencies updated.** Raised the `pi-coding-agent`, `pi-ai`, `pi-tui` dev pins to `^0.84.0`. Audited against the pi v0.84.0 breaking changes (renamed `ModelsRequestTransforms`, null-tolerant `getApiKeyAndHeaders` headers, dropped `message_update` partial fields, v4 session APIs); no code changes were needed and `tsc`/`typecheck` passes against 0.84.0.
49
+
50
+ ## [1.2.0] - 2026-07-26
51
+
52
+ ### Added
53
+
54
+ - **`permissions` config + `/agy` row + `AGY_SKIP_PERMISSIONS` env.** Controls
55
+ the new flag. Default `auto-approved` (required for non-interactive use); set
56
+ to `prompt` (`/agy` picker, or `AGY_SKIP_PERMISSIONS=0`) to disable - but
57
+ then any `run_command` hangs until you kill the call. Matches the bridge's
58
+ permissions knob.
59
+
60
+ ### Changed
61
+
62
+ - **Defers to `pi-antigravity-bridge` when it is installed.** The bridge now
63
+ ships both the streaming antigravity provider AND the `AskAntigravity` tool
64
+ (same shape as `pi-claude-bridge`). To avoid a duplicate-tool clash, this
65
+ extension detects the bridge at load and, if present, registers nothing -
66
+ silently. Detection does not use module resolution (pi isolates each
67
+ package's module root); it checks an in-process `Symbol.for` flag the bridge
68
+ sets AND the bridge's package.json at pi's install paths
69
+ (`@estebanforge/pi-antigravity-bridge/package.json`). Order-independent for
70
+ npm/git installs; for local/source installs relies on the in-process flag
71
+ (install the bridge first so it loads first). Without the bridge, behavior is
72
+ unchanged.
73
+
74
+ ### Fixed
75
+
76
+ - **`run_command` no longer hangs the tool.** `--mode accept-edits` auto-approves
77
+ file edits but NOT shell commands, so any task that triggered a `run_command`
78
+ hung forever on an unanswerable `y/n` prompt in non-interactive `-p` mode
79
+ (same root cause the pi-antigravity-bridge provider hit). The tool now passes
80
+ `--dangerously-skip-permissions` by default. Backported from the bridge.
81
+
82
+ ## [1.1.0] - 2026-07-25
83
+
84
+ ### Fixed
85
+
86
+ - **`CONV_ID_RE` rejected real agy conversation ids, silently breaking the
87
+ "continued conversation" feature.** The regex was
88
+ `/^[A-Za-z0-9]{1,128}$/` (no hyphens in the character class), but agy
89
+ conversation ids are hyphenated UUIDs (e.g.
90
+ `9e6fdc2f-f9f9-4096-95fc-7852528b50cc`, the very example in the source
91
+ comment). Every legitimate id failed validation, so `isContinuation`
92
+ was always `false`, `--conversation <id>` was never passed, and every
93
+ "continued" call quietly started a brand-new agy conversation instead
94
+ of resuming. Now allows hyphens in the body
95
+ (`/^[A-Za-z0-9][A-Za-z0-9-]{0,127}$/`) while preserving the threat
96
+ model: first char must be alphanumeric, so leading-dash flag-injection
97
+ values are still rejected. Present since 1.0.0; found by peer review.
98
+
99
+ ### Added
100
+
101
+ - **`mode` parameter** — replaces the previous `skipPermissions` boolean
102
+ with an explicit two-way enum: `plan` (review-only, `--mode plan`) and
103
+ `accept-edits` (agy applies edits, `--mode accept-edits`, default).
104
+ Use `plan` for cross-review and read-only tasks, `accept-edits` for
105
+ implementation.
106
+ - **`digest` parameter** — when true, the prompt is prefixed with
107
+ `(Use compact digests, not full file contents.)` to keep `agy` from
108
+ returning full file payloads. Default: `true` for `plan`,
109
+ `false` for `accept-edits`. Override per call.
110
+ - **Non-Gemini alias overlay** — `sonnet`, `opus`, and `gpt-oss` now
111
+ resolve to the exact agy strings `Claude Sonnet 4.6 (Thinking)`,
112
+ `Claude Opus 4.6 (Thinking)`, and `GPT-OSS 120B (Medium)`. A
113
+ static short-alias map is checked before the family parser, so
114
+ these names resolve even when `agy models` does not surface them
115
+ in the live catalog (older agy builds, plan-gated models). The
116
+ overlay entries are also merged with the live catalog at
117
+ extension load; live entries always win on case-insensitive
118
+ full-string equality, so an updated `agy models` listing takes
119
+ precedence over the hardcoded fallback. Borrowed from
120
+ `@bacnh85/pi-agy`'s static model map.
121
+ - **Effective `mode` and `digest` surfaced in `details`** — every
122
+ tool result now reports the resolved mode and whether the digest
123
+ prefix was applied, so the orchestrating model (and humans reading
124
+ logs) can see what flags were actually passed to `agy`.
125
+ - **Case-insensitive live-catalog lookup for overlay aliases.** When
126
+ `sonnet` / `opus` / `gpt-oss` resolve via the overlay, the lookup
127
+ against the live catalog is now case-insensitive so the
128
+ "live entries win" guarantee holds even if `agy models` lists the
129
+ same model under different casing than the hardcoded overlay.
130
+ Matches `mergeCatalog`'s dedup logic.
131
+
132
+ ### Changed
133
+
134
+ - **Breaking: `skipPermissions` parameter is removed.** Use `mode`
135
+ instead. The previous `skipPermissions: true` (which passed
136
+ `--dangerously-skip-permissions`) was a coarse proxy for the new
137
+ `mode: "accept-edits"` and is no longer the right primitive. Use
138
+ `mode: "plan"` for review-only flows. No callers in the wild
139
+ depend on the old boolean (the package shipped 2026-07-07), so
140
+ the break is contained to a single minor bump.
141
+ - **No `sandbox` enum value.** A peer review caught that agy's
142
+ `--sandbox` flag is an orthogonal shell-containment setting,
143
+ not an "edit preview" mode. Users who need shell containment
144
+ should set `AGY_EXTRA_ARGS=--sandbox` in their environment.
145
+ - **Tool description** now documents the `mode` and `digest`
146
+ affordances so the orchestrating model knows about them.
147
+
148
+ ## [1.0.1] - 2026-07-23
149
+
150
+ ### Fixed
151
+
152
+ - **`gemini-flash-latest` and `gemini-pro-latest` aliases now win over
153
+ versioned entries when no version is pinned.** Previously, asking for
154
+ `flash` resolved to the highest version of the flash family (e.g.
155
+ `Gemini 3.6 Flash (Medium)`), which is a concrete snapshot — not
156
+ Google's "latest release" pointer. The resolver now prefers entries
157
+ with `version: null` (the aliases that `parseModelLine` produces from
158
+ names like `Gemini Flash Latest`) over versioned entries. Falls back
159
+ to the highest version if no alias is present in the catalog, so
160
+ older agy builds without `*-latest` entries keep working.
161
+ - **Leading-dash values passed as `model` are rejected before reaching
162
+ argv.** A value like `--dangerously-skip-permissions` used to land
163
+ verbatim as the `--model` token; the tool now refuses it with a clear
164
+ error message, matching the `CONV_ID_RE` threat model already applied
165
+ to conversation ids.
166
+
167
+ ### Changed
168
+
169
+ - `modelParam` is now a plain `Type.String()` instead of a conditional
170
+ `StringEnum` built from the live catalog. The enum was too restrictive
171
+ when discovery succeeded (the common case): any tiered or pinned
172
+ alias like `"flash high"` or `"3.5 flash"` failed AJV validation
173
+ before `resolveModel` ever saw it. Plain `Type.String()` lets the
174
+ resolver handle every documented form and falls back to agy for
175
+ unknown slugs. The now-unused `StringEnum` import is gone.
176
+
177
+ ## [1.0.0] - 2026-07-07
178
+
179
+ Initial release.
180
+
181
+ ### Added
182
+
183
+ - **`AskAntigravity` tool** — delegates a self-contained sub-task to Google
184
+ Antigravity's `agy` CLI (the CLI for Gemini) via `agy -p`, streams stdout
185
+ as partial output, and returns the final response. The tool answers to
186
+ three names the CLI is known by — **gemini**, **antigravity**, and **agy**
187
+ — surfaced in its description so the model maps any of them to this single
188
+ tool.
189
+ - **Multi-turn conversations with agy** — optional `conversationId` param.
190
+ Omit for a one-shot (agy starts fresh); pass the id returned in a prior
191
+ call's result (`details.conversationId`) to resume that conversation with
192
+ full context. The agent decides per call which mode to use. On fresh runs
193
+ the extension discovers the new conversation id agy creates (snapshot +
194
+ diff of agy's conversations dir, the one technique borrowed from
195
+ [`antigravity-acp`](https://github.com/shubzkothekar/antigravity-acp)'s
196
+ `scan.ts`); on continued runs it passes `--conversation <id>` which agy
197
+ resumes natively. agy holds all state in its own SQLite DB; the extension
198
+ is otherwise stateless.
199
+ - **Friendly model aliases** — `flash`, `pro`, `gemini`, plus tier/version
200
+ qualifiers (`flash high`, `3.1 pro`). Aliases resolve to the exact
201
+ `agy models` string using numeric version comparison, with nearest-tier
202
+ fallback (Pro has no Medium → falls back to High; ties break toward the
203
+ higher tier so "latest and greatest" wins).
204
+ - **`/agy` slash command** — interactive picker (`SettingsList`) for the
205
+ default model and default thinking tier. If the project config shadows the
206
+ global, the change is written there so it actually takes effect; otherwise
207
+ it writes to global. Outside TUI (RPC/headless), prints a read-only status
208
+ snapshot.
209
+ - **Config file** — `~/.pi/agent/ask-antigravity.json` (global) merged over
210
+ `.pi/ask-antigravity.json` (project). Atomic writes (temp + rename).
211
+ - **Defaults** — model `flash`, thinking `medium` (Gemini 3.5 Flash Medium).
212
+ - **Circular-delegation guard** — refuses to spawn agy when the active Pi
213
+ provider is already `antigravity`/`agy`.
214
+ - **Process lifecycle** — spawned `agy` runs in a detached process group so
215
+ its own exec subprocesses are killed on abort/timeout (not orphaned); a
216
+ watchdog enforces the timeout cap directly (not just via agy's
217
+ `--print-timeout`); stdout/stderr decoded at the stream level for UTF-8
218
+ safety across pipe chunks; throttled status updates avoid O(n²) re-renders.
219
+ - **Environment support** — `AGY_BIN`, `AGY_EXTRA_ARGS`,
220
+ `AGY_CONVERSATIONS_DIR`.
@@ -77,6 +77,24 @@ const FAMILY_DEFAULT_TIER: Record<Family, ThinkingTier> = {
77
77
 
78
78
  const TIER_RANK: Record<ThinkingTier, number> = { low: 0, medium: 1, high: 2 };
79
79
 
80
+ /** pi thinking-level vocabulary -> agy tier, for the thinking/effort tool
81
+ * params. Unknown values fall to low (agy always thinks something). */
82
+ function levelToTier(level: string): ThinkingTier {
83
+ switch (level) {
84
+ case "minimal":
85
+ case "low":
86
+ return "low";
87
+ case "medium":
88
+ return "medium";
89
+ case "high":
90
+ case "xhigh":
91
+ case "max":
92
+ return "high";
93
+ default:
94
+ return "low";
95
+ }
96
+ }
97
+
80
98
  // Mode = which agy tool-loop policy to apply. Distinct from the alias layer.
81
99
  // "plan" → --mode plan (no edits; review-only)
82
100
  // "accept-edits" → --mode accept-edits (agy applies edits)
@@ -140,7 +158,12 @@ EXECUTION MODES (param: mode):
140
158
  - **accept-edits** (default): agy applies edits directly inside the workspace.
141
159
  - For agy's orthogonal \`--sandbox\` shell-containment flag, set the \`AGY_EXTRA_ARGS=--sandbox\` env var.
142
160
 
143
- COMPACT OUTPUT (param: digest): when true, the prompt is prefixed to request compact digests instead of full file contents. Defaults on for plan, off for accept-edits. Use true whenever you do not need full file payloads (review, exploration, planning).`;
161
+ COMPACT OUTPUT (param: digest): when true, the prompt is prefixed to request compact digests instead of full file contents. Defaults on for plan, off for accept-edits. Use true whenever you do not need full file payloads (review, exploration, planning).
162
+
163
+ THINKING LEVEL (params: thinking, effort - SYNONYMS for one knob):
164
+ - pi calls it thinking, agy calls it effort. Same thing. Pass ONE of the two.
165
+ - Values (pi vocabulary): minimal|low|medium|high|xhigh|max. Clamped to agy's low|medium|high; unknown values fall back to low. "peer review on high thinking" -> thinking: "high".
166
+ - An explicit level beats a tier embedded in model ("flash high") and the configured default. Omit both for the configured default.`;
144
167
 
145
168
  // --- Types -----------------------------------------------------------------
146
169
 
@@ -318,6 +341,10 @@ export function resolveModel(
318
341
  input: string,
319
342
  entries: ModelEntry[],
320
343
  defaultThinking: ThinkingTier,
344
+ /** Explicit thinking param (thinking/effort). Beats a tier embedded in
345
+ * the alias ("flash high") and the configured default; clamped to the
346
+ * family's real tiers, ignored for fixed-thinking families. */
347
+ preferredTier?: ThinkingTier,
321
348
  ): ResolvedModel | null {
322
349
  const lower = input.toLowerCase().trim();
323
350
 
@@ -400,6 +427,7 @@ export function resolveModel(
400
427
  if (familyTiers.size === 0) return toResolved(candidates[0].full, null); // no tiers on any entry
401
428
 
402
429
  const preferred =
430
+ preferredTier ??
403
431
  tier ??
404
432
  (familyTiers.has(defaultThinking) ? defaultThinking : FAMILY_DEFAULT_TIER[family]);
405
433
  const chosenTier = nearestTier([...familyTiers], preferred);
@@ -901,6 +929,18 @@ export default async function (pi: ExtensionAPI) {
901
929
  }),
902
930
  ),
903
931
  model: modelParam,
932
+ thinking: Type.Optional(
933
+ Type.String({
934
+ description:
935
+ "Thinking level (= agy effort tier). pi vocabulary: minimal|low|medium|high|xhigh|max, clamped to agy's low|medium|high. Overrides a tier embedded in `model`. Omit for the configured default.",
936
+ }),
937
+ ),
938
+ effort: Type.Optional(
939
+ Type.String({
940
+ description:
941
+ "Alias for `thinking` (agy's own name for the same knob). Pass ONE of the two; different values on both is an error.",
942
+ }),
943
+ ),
904
944
  mode: Type.Optional(
905
945
  Type.Union(
906
946
  [
@@ -945,8 +985,14 @@ export default async function (pi: ExtensionAPI) {
945
985
  // surface the resolved tier separately for identification.
946
986
  const cfg = loadConfig();
947
987
  const requestedModel = (args.model as string | undefined)?.trim() || cfg.defaultModel;
988
+ const thinkingArg = (args.thinking as string | undefined) ?? (args.effort as string | undefined);
948
989
  const resolved =
949
- resolveModel(requestedModel, discovered, cfg.defaultThinking) ?? { model: requestedModel };
990
+ resolveModel(
991
+ requestedModel,
992
+ discovered,
993
+ cfg.defaultThinking,
994
+ thinkingArg ? levelToTier(thinkingArg) : undefined,
995
+ ) ?? { model: requestedModel };
950
996
  const thinking: ThinkingTier = resolved.effort ?? cfg.defaultThinking;
951
997
  const mode: Mode = (args.mode as Mode | undefined) ?? "accept-edits";
952
998
  const useDigest = typeof args.digest === "boolean" ? args.digest : mode === "plan";
@@ -1050,8 +1096,29 @@ export default async function (pi: ExtensionAPI) {
1050
1096
  details: emptyDetails(requestedModel, null),
1051
1097
  };
1052
1098
  }
1099
+ if (
1100
+ typeof params.thinking === "string" &&
1101
+ typeof params.effort === "string" &&
1102
+ params.thinking !== params.effort
1103
+ ) {
1104
+ return {
1105
+ content: [
1106
+ {
1107
+ type: "text",
1108
+ text: "thinking and effort are synonyms for the same knob - pass one, not both with different values.",
1109
+ },
1110
+ ],
1111
+ details: emptyDetails(requestedModel, null),
1112
+ };
1113
+ }
1114
+ const thinkingArg = (params.thinking as string | undefined) ?? (params.effort as string | undefined);
1053
1115
  const resolved =
1054
- resolveModel(requestedModel, discovered, config.defaultThinking) ?? {
1116
+ resolveModel(
1117
+ requestedModel,
1118
+ discovered,
1119
+ config.defaultThinking,
1120
+ thinkingArg ? levelToTier(thinkingArg) : undefined,
1121
+ ) ?? {
1055
1122
  model: requestedModel,
1056
1123
  };
1057
1124
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@estebanforge/pi-ask-antigravity",
3
- "version": "1.2.4",
3
+ "version": "1.2.6",
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",
@@ -20,20 +20,18 @@
20
20
  },
21
21
  "repository": {
22
22
  "type": "git",
23
- "url": "git+https://github.com/EstebanForge/pi-ask-antigravity.git"
23
+ "url": "git+https://github.com/EstebanForge/pi-extensions.git",
24
+ "directory": "packages/pi-ask-antigravity"
24
25
  },
25
26
  "publishConfig": {
26
27
  "access": "public"
27
28
  },
28
29
  "type": "module",
29
- "scripts": {
30
- "typecheck": "tsc --noEmit",
31
- "test": "vitest run",
32
- "prepublishOnly": "npm run typecheck && npm test"
33
- },
34
30
  "files": [
35
31
  "extensions",
36
- "README.md"
32
+ "README.md",
33
+ "CHANGELOG.md",
34
+ "LICENSE"
37
35
  ],
38
36
  "pi": {
39
37
  "extensions": [
@@ -47,14 +45,5 @@
47
45
  "@earendil-works/pi-coding-agent": {
48
46
  "optional": true
49
47
  }
50
- },
51
- "devDependencies": {
52
- "@earendil-works/pi-coding-agent": "^0.84.0",
53
- "@earendil-works/pi-ai": "^0.84.0",
54
- "@earendil-works/pi-tui": "^0.84.0",
55
- "@types/node": "^22.0.0",
56
- "typebox": "^1.1.38",
57
- "typescript": "^5.8.0",
58
- "vitest": "^4.1.7"
59
48
  }
60
49
  }