feat(desktop): add agy lifecycle hook integration#5096
Conversation
Writes ~/.gemini/config/hooks.json with a "superset-lifecycle" entry on
app start, mapping agy's PreInvocation/PostInvocation/PreToolUse/PostToolUse/
Stop events to Superset lifecycle notifications via agy-hook.sh.
Tool-use hooks use the matcher+hooks nested format required by agy;
PreToolUse returns {"decision":"allow"} to permit execution. Stale
hook entries from previous installs are cleaned up on each app start.
|
Ready to review this PR? Stage has broken it down into 8 individual chapters for you: Chapters generated by Stage for commit 68235b8 on Jun 4, 2026 8:38pm UTC. |
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds Google’s Antigravity CLI (agy) as a built-in terminal agent across the shared manifest, desktop setup tooling (wrapper + hooks), UI preset icons, and supporting docs/tests.
Changes:
- Registers
agyinBUILTIN_TERMINAL_AGENTSand adds preset icon wiring (PRESET_ICONS). - Introduces desktop setup actions/targets for
agy, plus wrapper + hook script + hooks.json generation. - Extends agent setup tests and updates external-files documentation.
Reviewed changes
Copilot reviewed 11 out of 13 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/ui/src/assets/icons/preset-icons/index.ts | Imports/exports and registers the new agy preset icon set. |
| packages/ui/src/assets/icons/preset-icons/agy.svg | Adds the light-variant Antigravity SVG asset. |
| packages/ui/src/assets/icons/preset-icons/agy-white.svg | Adds the dark-variant asset (currently identical to light). |
| packages/shared/src/builtin-terminal-agents.ts | Adds agy to the built-in terminal agent manifest. |
| apps/desktop/src/main/lib/agent-setup/templates/agy-hook.template.sh | Adds an agy lifecycle hook script template that dispatches events to Superset endpoints. |
| apps/desktop/src/main/lib/agent-setup/desktop-agent-setup.ts | Registers agy setup runners (hook script, wrapper, hooks.json). |
| apps/desktop/src/main/lib/agent-setup/desktop-agent-capabilities.ts | Adds agy setup actions and a new setup target. |
| apps/desktop/src/main/lib/agent-setup/agent-wrappers.ts | Barrel re-exports agy wrapper/hook helpers. |
| apps/desktop/src/main/lib/agent-setup/agent-wrappers.test.ts | Adds tests for agy wrapper + hook script + hooks.json behavior. |
| apps/desktop/src/main/lib/agent-setup/agent-wrappers-agy.ts | Implements agy wrapper and hook/hook-json generation logic. |
| apps/desktop/plans/20260601-antigravity-builtin-agent.md | Adds an implementation plan document (currently inconsistent with shipped hook changes). |
| apps/desktop/docs/EXTERNAL_FILES.md | Documents the new agy wrapper as an external file. |
| apps/desktop/docs/20260601-antigravity-builtin-agent-design.md | Adds a design doc (currently inconsistent with shipped hook changes + icon filenames). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| case "$EVENT_TYPE" in | ||
| PreInvocation) EVENT_TYPE="Start" ;; | ||
| PostInvocation) EVENT_TYPE="Stop" ;; | ||
| PreToolUse) EVENT_TYPE="PermissionRequest" ;; | ||
| PostToolUse) EVENT_TYPE="Start" ;; | ||
| Stop) ;; | ||
| *) exit 0 ;; | ||
| esac |
| existing[AGY_HOOKS_JSON_KEY] = { | ||
| PreInvocation: [{ command: `${hookScriptPath} PreInvocation` }], | ||
| PostInvocation: [{ command: `${hookScriptPath} PostInvocation` }], | ||
| PreToolUse: [ | ||
| { matcher: ".*", hooks: [{ command: `${hookScriptPath} PreToolUse` }] }, | ||
| ], | ||
| PostToolUse: [ | ||
| { matcher: ".*", hooks: [{ command: `${hookScriptPath} PostToolUse` }] }, | ||
| ], | ||
| Stop: [{ command: `${hookScriptPath} Stop` }], | ||
| }; |
| - The Superset-managed binary at `~/.superset/bin/agy` (and the `SUPERSET_AGENT_ID=agy` identity env var that wires the agent to future hook integrations) | ||
| - A documented configuration path for first-class features | ||
|
|
||
| The fix is a 5-touchpoint integration matching the existing pattern for built-in terminal agents. Antigravity CLI is brand new (v1.0.4 released 2026-06-01) and has no documented hook system yet, so notification hook integration is explicitly deferred to a follow-up. |
| **Asset creation:** copy `apps/desktop/src/renderer/assets/app-icons/antigravity.svg` to two new files in the preset-icons directory: | ||
|
|
||
| - `packages/ui/src/assets/icons/preset-icons/agy.svg` (light variant) | ||
| - `packages/ui/src/assets/icons/preset-icons/agy-dark.svg` (dark variant — copy of the same file for now) |
Greptile SummaryThis PR integrates the Antigravity CLI (
Confidence Score: 3/5The integration follows established patterns and is well-tested, but a defect in the hooks.json merge path can silently wipe user-defined hook entries when the file is malformed. The hooks.json merge in getAgyHooksJsonContent catches JSON parse errors and continues with an empty object, which causes createAgyHooksJson to overwrite the file with only the Superset entry — permanently deleting any user hooks the file contained. The log message (merging carefully) actively misleads operators debugging the loss. This is in a path that runs on every app start. agent-wrappers-agy.ts (merge error handling) and agy-hook.template.sh (json_escape and session_id extraction) deserve a second look before merge.
|
| Filename | Overview |
|---|---|
| apps/desktop/src/main/lib/agent-setup/agent-wrappers-agy.ts | New module wiring agy lifecycle hooks; contains a bug where a corrupted hooks.json silently destroys all user-defined entries during the merge step. |
| apps/desktop/src/main/lib/agent-setup/templates/agy-hook.template.sh | Shell hook script mapping agy events to Superset lifecycle events; json_escape omits newline/control-char handling and session_id extraction uses fragile chained grep. |
| apps/desktop/src/main/lib/agent-setup/agent-wrappers.test.ts | Good test coverage added: wrapper passthrough, hook script marker, hooks.json structure, stale-entry replacement, and idempotency are all exercised. |
| apps/desktop/src/main/lib/agent-setup/desktop-agent-capabilities.ts | Registers three new agy setup actions and target definition; straightforward additive change consistent with existing agent entries. |
| apps/desktop/src/main/lib/agent-setup/desktop-agent-setup.ts | Wires the three new agy action runners into the dispatch table; clean, minimal change. |
| packages/shared/src/builtin-terminal-agents.ts | Adds agy as a built-in terminal agent with id, label, description, command, and promptCommand; consistent with all other agent entries. |
| apps/desktop/src/main/lib/agent-setup/agent-wrappers.ts | Re-exports all public symbols from the new agy module; no logic changes. |
Sequence Diagram
sequenceDiagram
participant App as Desktop App (startup)
participant FS as ~/.gemini/config/hooks.json
participant AGY as agy CLI
participant Hook as agy-hook.sh
participant SS as Superset Notification
App->>FS: createAgyHooksJson() — write superset-lifecycle entry
App->>Hook: createAgyHookScript() — write agy-hook.sh (0755)
AGY->>Hook: PreInvocation (stdin: JSON)
Hook->>SS: "POST eventType=Start"
AGY->>Hook: PreToolUse (stdin: JSON)
Hook-->>AGY: "stdout {decision:allow}"
Hook->>SS: "POST eventType=PermissionRequest"
AGY->>Hook: PostToolUse (stdin: JSON)
Hook->>SS: "POST eventType=Start"
AGY->>Hook: PostInvocation (stdin: JSON)
Hook->>SS: "POST eventType=Stop"
AGY->>Hook: Stop (stdin: JSON)
Hook->>SS: "POST eventType=Stop"
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 3
apps/desktop/src/main/lib/agent-setup/agent-wrappers-agy.ts:83-87
**Misleading error handling silently destroys user hooks**
When `hooks.json` exists but contains invalid JSON, `JSON.parse` throws, `existing` stays as `{}` (its initial value), and the function proceeds to write a file containing only the new `superset-lifecycle` entry. All user-defined hooks are permanently lost. The log message says "merging carefully," which is the opposite of what actually happens — there is no merge.
A safer approach is to re-throw (or return early) so that `createAgyHooksJson` can catch the failure and skip the write, preserving the corrupted file intact until a human can inspect it.
### Issue 2 of 3
apps/desktop/src/main/lib/agent-setup/templates/agy-hook.template.sh:30-32
`json_escape` only escapes backslashes and double-quotes; it leaves newlines and other control characters (` `, `
`, carriage-returns, etc.) unescaped. If any of the four env-var values happen to contain a literal newline, the resulting `PAYLOAD` string is not valid JSON and the host-service call silently fails, falling back to the v1 path with no event fired.
```suggestion
json_escape() {
printf '%s' "$1" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/\n/\\n/g' -e 's/\r/\\r/g' -e 's/\t/\\t/g'
}
```
### Issue 3 of 3
apps/desktop/src/main/lib/agent-setup/templates/agy-hook.template.sh:16
**Fragile regex-based JSON field extraction**
The two-grep chain to extract `session_id` can produce incorrect results when the key appears in a nested object earlier in the JSON blob, or when the value contains escaped characters. If the first grep matches more than one occurrence, `HOOK_SESSION_ID` silently receives the last match rather than the top-level one. The result is an empty or wrong `sessionId` in both the host-service payload and the v1 fallback — no crash, but session tracking is silently wrong. Using `jq -r '.session_id // ""'` (if available) or a `python3 -c` one-liner as a fallback would be more reliable and self-documenting.
Reviews (1): Last reviewed commit: "feat(desktop): add agy lifecycle hook in..." | Re-trigger Greptile
| } catch { | ||
| console.warn( | ||
| "[agent-setup] Could not parse existing ~/.gemini/config/hooks.json, merging carefully", | ||
| ); | ||
| } |
There was a problem hiding this comment.
Misleading error handling silently destroys user hooks
When hooks.json exists but contains invalid JSON, JSON.parse throws, existing stays as {} (its initial value), and the function proceeds to write a file containing only the new superset-lifecycle entry. All user-defined hooks are permanently lost. The log message says "merging carefully," which is the opposite of what actually happens — there is no merge.
A safer approach is to re-throw (or return early) so that createAgyHooksJson can catch the failure and skip the write, preserving the corrupted file intact until a human can inspect it.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/main/lib/agent-setup/agent-wrappers-agy.ts
Line: 83-87
Comment:
**Misleading error handling silently destroys user hooks**
When `hooks.json` exists but contains invalid JSON, `JSON.parse` throws, `existing` stays as `{}` (its initial value), and the function proceeds to write a file containing only the new `superset-lifecycle` entry. All user-defined hooks are permanently lost. The log message says "merging carefully," which is the opposite of what actually happens — there is no merge.
A safer approach is to re-throw (or return early) so that `createAgyHooksJson` can catch the failure and skip the write, preserving the corrupted file intact until a human can inspect it.
How can I resolve this? If you propose a fix, please make it concise.| json_escape() { | ||
| printf '%s' "$1" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' | ||
| } |
There was a problem hiding this comment.
json_escape only escapes backslashes and double-quotes; it leaves newlines and other control characters ( , , carriage-returns, etc.) unescaped. If any of the four env-var values happen to contain a literal newline, the resulting PAYLOAD string is not valid JSON and the host-service call silently fails, falling back to the v1 path with no event fired.
| json_escape() { | |
| printf '%s' "$1" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' | |
| } | |
| json_escape() { | |
| printf '%s' "$1" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/\n/\\n/g' -e 's/\r/\\r/g' -e 's/\t/\\t/g' | |
| } |
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/main/lib/agent-setup/templates/agy-hook.template.sh
Line: 30-32
Comment:
`json_escape` only escapes backslashes and double-quotes; it leaves newlines and other control characters (` `, `
`, carriage-returns, etc.) unescaped. If any of the four env-var values happen to contain a literal newline, the resulting `PAYLOAD` string is not valid JSON and the host-service call silently fails, falling back to the v1 path with no event fired.
```suggestion
json_escape() {
printf '%s' "$1" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/\n/\\n/g' -e 's/\r/\\r/g' -e 's/\t/\\t/g'
}
```
How can I resolve this? If you propose a fix, please make it concise.| esac | ||
|
|
||
| EVENT_TYPE="$1" | ||
| HOOK_SESSION_ID=$(printf '%s' "$INPUT" | grep -oE '"session_id"[[:space:]]*:[[:space:]]*"[^"]*"' | grep -oE '"[^"]*"$' | tr -d '"') |
There was a problem hiding this comment.
Fragile regex-based JSON field extraction
The two-grep chain to extract session_id can produce incorrect results when the key appears in a nested object earlier in the JSON blob, or when the value contains escaped characters. If the first grep matches more than one occurrence, HOOK_SESSION_ID silently receives the last match rather than the top-level one. The result is an empty or wrong sessionId in both the host-service payload and the v1 fallback — no crash, but session tracking is silently wrong. Using jq -r '.session_id // ""' (if available) or a python3 -c one-liner as a fallback would be more reliable and self-documenting.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/main/lib/agent-setup/templates/agy-hook.template.sh
Line: 16
Comment:
**Fragile regex-based JSON field extraction**
The two-grep chain to extract `session_id` can produce incorrect results when the key appears in a nested object earlier in the JSON blob, or when the value contains escaped characters. If the first grep matches more than one occurrence, `HOOK_SESSION_ID` silently receives the last match rather than the top-level one. The result is an empty or wrong `sessionId` in both the host-service payload and the v1 fallback — no crash, but session tracking is silently wrong. Using `jq -r '.session_id // ""'` (if available) or a `python3 -c` one-liner as a fallback would be more reliable and self-documenting.
How can I resolve this? If you propose a fix, please make it concise.
📝 WalkthroughWalkthroughAdds Antigravity CLI (agy) as a built-in terminal agent by registering it in the shared manifest, adding UI icons, generating a managed wrapper and lifecycle hook integration, wiring setup actions into the desktop bootstrap, and expanding tests and documentation. ChangesAntigravity Agent Built-in Integration
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
1 issue found across 13 files
Architecture diagram
sequenceDiagram
participant Desktop as Desktop App (Main)
participant Setup as Agent Setup
participant FS as File System
participant Wrapper as ~/.superset/bin/agy
participant AgyCLI as agy CLI Process
participant HookScript as agy-hook.sh
participant HostSvc as Superset Host Service
participant LocalHook as http://127.0.0.1/hook/complete
Note over Desktop,LocalHook: App Startup – Setup Phase
Desktop->>Setup: runAgentSetup("agy")
Setup->>FS: install wrapper → ~/.superset/bin/agy
Setup->>FS: write agy-hook.sh with marker + template
Setup->>FS: read existing ~/.gemini/config/hooks.json
alt Stale entries found (old path or flat format)
Setup->>FS: remove "superset-lifecycle" key if references agy-hook.sh
Setup->>FS: also remove legacy flat {command} entries
end
Setup->>FS: write hooks.json with "superset-lifecycle" entry
Note over FS: PreInvocation/PostInvocation/Stop: flat command<br/>PreToolUse/PostToolUse: {matcher:".*", hooks:[{command:...}]}
Note over Desktop,LocalHook: Runtime – agy Invocation
User->>Wrapper: execute agy (interactive or prompt)
Wrapper->>Wrapper: export SUPERSET_AGENT_ID="agy"
Wrapper->>AgyCLI: exec "$REAL_BIN" "$@"
Note over AgyCLI,HookScript: Hook Events Fired by agy
AgyCLI->>HookScript: fire PreInvocation (event type in $1)
HookScript->>HookScript: map to Superset "Start"
alt SUPERSET_HOST_AGENT_HOOK_URL is set
HookScript->>HostSvc: POST with terminalId, eventType, agentId, sessionId
HostSvc-->>HookScript: HTTP 2xx
else
HookScript->>LocalHook: GET?paneId=...&eventType=Start
LocalHook-->>HookScript: HTTP 2xx
end
HookScript-->>AgyCLI: stdout {}
AgyCLI->>HookScript: fire PreToolUse (event type $1)
HookScript->>HookScript: map to "PermissionRequest"
HookScript-->>AgyCLI: stdout {"decision":"allow"} ← unblocks agy
alt send notification (same as above)
HookScript->>HostSvc: POST or GET
end
AgyCLI->>HookScript: fire PostToolUse (event type $1)
HookScript->>HookScript: map to "Start"
HookScript-->>AgyCLI: stdout {}
AgyCLI->>HookScript: fire Stop (e.g., on abort)
HookScript->>HookScript: map to "Stop"
HookScript-->>AgyCLI: stdout {}
AgyCLI->>HookScript: fire PostInvocation (session ends)
HookScript->>HookScript: map to "Stop"
HookScript-->>AgyCLI: stdout {}
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/desktop/docs/20260601-antigravity-builtin-agent-design.md`:
- Line 37: Locate the fenced code blocks in the document that use bare triple
backticks (``` with no language) and add appropriate language identifiers (e.g.,
"text", "mermaid", "bash") to each opening fence to satisfy markdownlint MD040;
specifically update the anonymous code blocks around the shown closing fence and
the other anonymous blocks referenced so they begin like ```text or ```mermaid
or ```bash as appropriate for their contents.
- Line 5: Update the design doc text that currently claims AGY hook integration
is deferred to reflect the shipped implementation: replace language at the
referenced sections (lines ~5, 17-18, 28-29, and 301-307) that says "deferred/no
documented format" with explicit documentation that the setup code adds the
agy-hook-script and agy-hooks-json actions and wires them into the AGY target;
describe the actual hook format and registration flow, update any examples to
show agy-hook-script and agy-hooks-json usage, and remove or change any TODOs
about deferral so the narrative matches the implemented behavior (including any
notes about tests and manifest/wrapper integration).
In `@apps/desktop/plans/20260601-antigravity-builtin-agent.md`:
- Line 25: The plan references two different dark-icon filenames (agy-white.svg
vs agy-dark.svg) causing inconsistency; pick the canonical name (e.g.,
agy-dark.svg), then update every reference in this plan and the other noted
occurrences to use that single filename (replace agy-white.svg → agy-dark.svg or
vice versa) so all docs consistently mention the same asset name (ensure you
update all instances: agy-white.svg and agy-dark.svg).
- Line 7: Update the stale sentence "Notification hook integration is
deferred..." to state that AGY hook integration shipped and is wired into the
desktop setup (it now includes AGY hook-script/hooks-json actions), and adjust
the later section that repeats this claim (the paragraph around the original
mention at the end of the plan) to reflect the same reality; keep the note that
the wrapper exports SUPERSET_AGENT_ID=agy and that future changes remain
additive.
In `@apps/desktop/src/main/lib/agent-setup/agent-wrappers-agy.ts`:
- Around line 79-83: The parsed hooks.json may contain non-object entries (e.g.,
null) causing property access errors; after reading/parsing into existing (from
globalPath) validate that existing is an object and that each hook entry is an
object before accessing properties like spec.PreInvocation or iterating entries
(also apply same guard to the logic around lines 91-103). If the file is
malformed, either skip those entries or coerce them into a safe default (e.g.,
empty object/empty spec) and log a warning; ensure checks use typeof ===
"object" && entry !== null before accessing spec.PreInvocation or other nested
fields.
- Around line 123-131: The generated command strings embed hookScriptPath
unquoted, which breaks when the path contains spaces or shell metacharacters;
update the template literals that build the command (the entries for
PreInvocation, PostInvocation, PreToolUse hooks, PostToolUse hooks, and Stop) to
wrap the hookScriptPath in shell quotes so the path is treated as a single token
(e.g., change `${hookScriptPath} PreInvocation` to `"<hookScriptPath>"
PreInvocation`-style quoting by using `"${hookScriptPath}"` in the template or a
small helper that safely shell-quotes the path) and apply the same fix to all
occurrences (PreInvocation, PostInvocation, PreToolUse, PostToolUse, Stop).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 82e46759-6044-4698-9987-7278b30a2d45
⛔ Files ignored due to path filters (2)
packages/ui/src/assets/icons/preset-icons/agy-white.svgis excluded by!**/*.svgpackages/ui/src/assets/icons/preset-icons/agy.svgis excluded by!**/*.svg
📒 Files selected for processing (11)
apps/desktop/docs/20260601-antigravity-builtin-agent-design.mdapps/desktop/docs/EXTERNAL_FILES.mdapps/desktop/plans/20260601-antigravity-builtin-agent.mdapps/desktop/src/main/lib/agent-setup/agent-wrappers-agy.tsapps/desktop/src/main/lib/agent-setup/agent-wrappers.test.tsapps/desktop/src/main/lib/agent-setup/agent-wrappers.tsapps/desktop/src/main/lib/agent-setup/desktop-agent-capabilities.tsapps/desktop/src/main/lib/agent-setup/desktop-agent-setup.tsapps/desktop/src/main/lib/agent-setup/templates/agy-hook.template.shpackages/shared/src/builtin-terminal-agents.tspackages/ui/src/assets/icons/preset-icons/index.ts
| |---|---| | ||
| | `apps/desktop/src/main/lib/agent-setup/agent-wrappers-agy.ts` | Wrapper generator for `~/.superset/bin/agy` | | ||
| | `packages/ui/src/assets/icons/preset-icons/agy.svg` | Light-variant Antigravity icon | | ||
| | `packages/ui/src/assets/icons/preset-icons/agy-white.svg` | Dark-variant Antigravity icon | |
There was a problem hiding this comment.
Normalize AGY dark icon naming across docs (agy-dark.svg vs agy-white.svg).
This plan uses agy-white.svg, while companion docs in this PR describe agy-dark.svg. Pick one canonical filename and update references to prevent follow-up implementation drift.
Also applies to: 353-354, 365-365, 373-373, 384-385, 467-468
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/desktop/plans/20260601-antigravity-builtin-agent.md` at line 25, The
plan references two different dark-icon filenames (agy-white.svg vs
agy-dark.svg) causing inconsistency; pick the canonical name (e.g.,
agy-dark.svg), then update every reference in this plan and the other noted
occurrences to use that single filename (replace agy-white.svg → agy-dark.svg or
vice versa) so all docs consistently mention the same asset name (ensure you
update all instances: agy-white.svg and agy-dark.svg).
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/desktop/src/main/lib/agent-setup/agent-wrappers.test.ts (1)
947-949:⚠️ Potential issue | 🟠 Major | ⚡ Quick winAGY marker expectation is stale after the version bump.
Line 948 still expects
# Superset agy hook v2, butAGY_HOOK_MARKERis now v3, so this test will fail.Suggested fix
- expect(AGY_HOOK_MARKER).toBe("# Superset agy hook v2"); + expect(AGY_HOOK_MARKER).toBe("# Superset agy hook v3");🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/desktop/src/main/lib/agent-setup/agent-wrappers.test.ts` around lines 947 - 949, The test assertion for AGY_HOOK_MARKER is stale: update the expectation in the test (the assertion comparing AGY_HOOK_MARKER) from "# Superset agy hook v2" to the new marker string "# Superset agy hook v3" (leave COPILOT_HOOK_MARKER check as-is), so the spec that references AGY_HOOK_MARKER matches the current constant value.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/desktop/src/main/lib/agent-setup/agent-wrappers-agy.ts`:
- Around line 89-112: readExistingAgyHooksJson currently throws on JSON.parse or
validation failures which can abort setup; change it to swallow parse/type
errors and return a safe empty AgyHooksJson instead while emitting a warning.
Specifically, in readExistingAgyHooksJson (and likewise in any helper
getAgyHooksJsonContent used by createAgyHooksJson), catch JSON.parse errors and
non-isRecord validation failures and return {} rather than throwing, and log a
concise warning (use the existing logger or console.warn) that the hooks.json
was malformed and will be replaced; this prevents createAgyHooksJson / the setup
runner from aborting on a bad ~/.gemini/config/hooks.json.
In `@apps/desktop/src/main/lib/agent-setup/templates/agy-hook.template.sh`:
- Around line 32-37: The case mapping for EVENT_TYPE in agy-hook.template.sh is
incorrect: the PostToolUse branch currently sets EVENT_TYPE to "Stop" but per
the AGY lifecycle contract PostToolUse must map to "Start"; update the case
statement so the PostToolUse) branch sets EVENT_TYPE="Start" (leave
PreInvocation->Start, PostInvocation->Stop, PreToolUse->PermissionRequest, Stop
unchanged).
---
Outside diff comments:
In `@apps/desktop/src/main/lib/agent-setup/agent-wrappers.test.ts`:
- Around line 947-949: The test assertion for AGY_HOOK_MARKER is stale: update
the expectation in the test (the assertion comparing AGY_HOOK_MARKER) from "#
Superset agy hook v2" to the new marker string "# Superset agy hook v3" (leave
COPILOT_HOOK_MARKER check as-is), so the spec that references AGY_HOOK_MARKER
matches the current constant value.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 68683106-4304-49ad-90ad-b6035356d2f4
📒 Files selected for processing (6)
apps/desktop/docs/20260601-antigravity-builtin-agent-design.mdapps/desktop/plans/20260601-antigravity-builtin-agent.mdapps/desktop/src/main/lib/agent-setup/agent-wrappers-agy.tsapps/desktop/src/main/lib/agent-setup/agent-wrappers.test.tsapps/desktop/src/main/lib/agent-setup/notify-hook.test.tsapps/desktop/src/main/lib/agent-setup/templates/agy-hook.template.sh
✅ Files skipped from review due to trivial changes (1)
- apps/desktop/plans/20260601-antigravity-builtin-agent.md
| function readExistingAgyHooksJson(globalPath: string): AgyHooksJson { | ||
| if (!fs.existsSync(globalPath)) { | ||
| return {}; | ||
| } | ||
|
|
||
| const rawContent = fs.readFileSync(globalPath, "utf-8"); | ||
| let parsed: unknown; | ||
| try { | ||
| parsed = JSON.parse(rawContent); | ||
| } catch (error) { | ||
| throw new Error( | ||
| "[agent-setup] Invalid ~/.gemini/config/hooks.json; refusing to overwrite malformed file.", | ||
| { cause: error }, | ||
| ); | ||
| } | ||
|
|
||
| if (!isRecord(parsed)) { | ||
| throw new Error( | ||
| "[agent-setup] Expected ~/.gemini/config/hooks.json to contain a JSON object.", | ||
| ); | ||
| } | ||
|
|
||
| return parsed; | ||
| } |
There was a problem hiding this comment.
Unhandled hooks.json parse errors can abort setup actions.
Line 205 calls getAgyHooksJsonContent, and parse/type errors thrown in Lines 89-112 are not handled in createAgyHooksJson. Given the direct setup runner execution path, a malformed ~/.gemini/config/hooks.json can break the AGY setup flow.
Suggested fix
export function createAgyHooksJson(): void {
const hookScriptPath = getAgyHookScriptPath();
const globalPath = getAgyHooksJsonPath();
- const content = getAgyHooksJsonContent(hookScriptPath);
+ let content: string;
+ try {
+ content = getAgyHooksJsonContent(hookScriptPath);
+ } catch (error) {
+ console.warn(
+ "[agent-setup] Skipping agy hooks.json update due to invalid existing file",
+ error,
+ );
+ return;
+ }
const dir = path.dirname(globalPath);
fs.mkdirSync(dir, { recursive: true });
const changed = writeFileIfChanged(globalPath, content, 0o644);Also applies to: 202-206
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/desktop/src/main/lib/agent-setup/agent-wrappers-agy.ts` around lines 89
- 112, readExistingAgyHooksJson currently throws on JSON.parse or validation
failures which can abort setup; change it to swallow parse/type errors and
return a safe empty AgyHooksJson instead while emitting a warning. Specifically,
in readExistingAgyHooksJson (and likewise in any helper getAgyHooksJsonContent
used by createAgyHooksJson), catch JSON.parse errors and non-isRecord validation
failures and return {} rather than throwing, and log a concise warning (use the
existing logger or console.warn) that the hooks.json was malformed and will be
replaced; this prevents createAgyHooksJson / the setup runner from aborting on a
bad ~/.gemini/config/hooks.json.
| case "$EVENT_TYPE" in | ||
| PreInvocation) EVENT_TYPE="Start" ;; | ||
| PostInvocation) EVENT_TYPE="Stop" ;; | ||
| PreToolUse) EVENT_TYPE="PermissionRequest" ;; | ||
| PostToolUse) EVENT_TYPE="Stop" ;; | ||
| Stop) ;; |
There was a problem hiding this comment.
PostToolUse is mapped to the wrong lifecycle event.
Line 36 maps PostToolUse to Stop; this conflicts with the stated AGY lifecycle contract (PostToolUse -> Start) and can produce incorrect lifecycle transitions during tool execution.
Suggested fix
- PostToolUse) EVENT_TYPE="Stop" ;;
+ PostToolUse) EVENT_TYPE="Start" ;;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| case "$EVENT_TYPE" in | |
| PreInvocation) EVENT_TYPE="Start" ;; | |
| PostInvocation) EVENT_TYPE="Stop" ;; | |
| PreToolUse) EVENT_TYPE="PermissionRequest" ;; | |
| PostToolUse) EVENT_TYPE="Stop" ;; | |
| Stop) ;; | |
| case "$EVENT_TYPE" in | |
| PreInvocation) EVENT_TYPE="Start" ;; | |
| PostInvocation) EVENT_TYPE="Stop" ;; | |
| PreToolUse) EVENT_TYPE="PermissionRequest" ;; | |
| PostToolUse) EVENT_TYPE="Start" ;; | |
| Stop) ;; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/desktop/src/main/lib/agent-setup/templates/agy-hook.template.sh` around
lines 32 - 37, The case mapping for EVENT_TYPE in agy-hook.template.sh is
incorrect: the PostToolUse branch currently sets EVENT_TYPE to "Stop" but per
the AGY lifecycle contract PostToolUse must map to "Start"; update the case
statement so the PostToolUse) branch sets EVENT_TYPE="Start" (leave
PreInvocation->Start, PostInvocation->Stop, PreToolUse->PermissionRequest, Stop
unchanged).
There was a problem hiding this comment.
3 issues found across 6 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/desktop/src/main/lib/agent-setup/agent-wrappers.test.ts">
<violation number="1" location="apps/desktop/src/main/lib/agent-setup/agent-wrappers.test.ts:595">
P2: The agy hook script test still omits the critical `PreToolUse` `{"decision":"allow"}` stdout assertion, so a regression that makes tool-use hooks block execution would go undetected.</violation>
</file>
<file name="apps/desktop/src/main/lib/agent-setup/templates/agy-hook.template.sh">
<violation number="1" location="apps/desktop/src/main/lib/agent-setup/templates/agy-hook.template.sh:36">
P1: `PostToolUse` is mapped to `Stop`, but the documented lifecycle contract (in the PR description) specifies `PostToolUse → Start`. After a tool finishes executing, the agent resumes processing — signaling `Stop` here will produce incorrect lifecycle transitions and may confuse the renderer's working-state indicator.</violation>
</file>
<file name="apps/desktop/src/main/lib/agent-setup/agent-wrappers-agy.ts">
<violation number="1" location="apps/desktop/src/main/lib/agent-setup/agent-wrappers-agy.ts:142">
P1: Unhandled parse error from `readExistingAgyHooksJson` will propagate up through `getAgyHooksJsonContent` and abort the entire setup runner if a user's `~/.gemini/config/hooks.json` is malformed. The previous code gracefully caught parse errors and continued. Wrap this call in a try/catch to log a warning and return early (or fall back to an empty object) rather than crashing the setup flow.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| PreInvocation) EVENT_TYPE="Start" ;; | ||
| PostInvocation) EVENT_TYPE="Stop" ;; | ||
| PreToolUse) EVENT_TYPE="PermissionRequest" ;; | ||
| PostToolUse) EVENT_TYPE="Stop" ;; |
There was a problem hiding this comment.
P1: PostToolUse is mapped to Stop, but the documented lifecycle contract (in the PR description) specifies PostToolUse → Start. After a tool finishes executing, the agent resumes processing — signaling Stop here will produce incorrect lifecycle transitions and may confuse the renderer's working-state indicator.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/main/lib/agent-setup/templates/agy-hook.template.sh, line 36:
<comment>`PostToolUse` is mapped to `Stop`, but the documented lifecycle contract (in the PR description) specifies `PostToolUse → Start`. After a tool finishes executing, the agent resumes processing — signaling `Stop` here will produce incorrect lifecycle transitions and may confuse the renderer's working-state indicator.</comment>
<file context>
@@ -13,22 +13,48 @@ case "$1" in
PostInvocation) EVENT_TYPE="Stop" ;;
PreToolUse) EVENT_TYPE="PermissionRequest" ;;
- PostToolUse) EVENT_TYPE="Start" ;;
+ PostToolUse) EVENT_TYPE="Stop" ;;
Stop) ;;
*) exit 0 ;;
</file context>
| PostToolUse) EVENT_TYPE="Stop" ;; | |
| PostToolUse) EVENT_TYPE="Start" ;; |
| */ | ||
| export function getAgyHooksJsonContent(hookScriptPath: string): string { | ||
| const globalPath = getAgyHooksJsonPath(); | ||
| const existing = readExistingAgyHooksJson(globalPath); |
There was a problem hiding this comment.
P1: Unhandled parse error from readExistingAgyHooksJson will propagate up through getAgyHooksJsonContent and abort the entire setup runner if a user's ~/.gemini/config/hooks.json is malformed. The previous code gracefully caught parse errors and continued. Wrap this call in a try/catch to log a warning and return early (or fall back to an empty object) rather than crashing the setup flow.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/main/lib/agent-setup/agent-wrappers-agy.ts, line 142:
<comment>Unhandled parse error from `readExistingAgyHooksJson` will propagate up through `getAgyHooksJsonContent` and abort the entire setup runner if a user's `~/.gemini/config/hooks.json` is malformed. The previous code gracefully caught parse errors and continued. Wrap this call in a try/catch to log a warning and return early (or fall back to an empty object) rather than crashing the setup flow.</comment>
<file context>
@@ -74,38 +139,22 @@ export function getAgyHookScriptContent(): string {
- "[agent-setup] Could not parse existing ~/.gemini/config/hooks.json, merging carefully",
- );
- }
+ const existing = readExistingAgyHooksJson(globalPath);
// Remove all entries whose commands reference our hook script (covers key
</file context>
| @@ -57,7 +57,11 @@ mock.module("node:os", () => ({ | |||
| })); | |||
There was a problem hiding this comment.
P2: The agy hook script test still omits the critical PreToolUse {"decision":"allow"} stdout assertion, so a regression that makes tool-use hooks block execution would go undetected.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/main/lib/agent-setup/agent-wrappers.test.ts, line 595:
<comment>The agy hook script test still omits the critical `PreToolUse` `{"decision":"allow"}` stdout assertion, so a regression that makes tool-use hooks block execution would go undetected.</comment>
<file context>
@@ -591,10 +591,13 @@ exit 0
expect(script).toContain("PreToolUse");
expect(script).toContain("PostToolUse");
+ expect(script).toContain('PostToolUse) EVENT_TYPE="Stop" ;;');
+ expect(script).toContain("jq -r 'try (.session_id // empty) catch empty'");
});
</file context>
| })); | |
| expect(script).toContain("jq -r 'try (.session_id // empty) catch empty'"); | |
| expect(script).toContain('PreToolUse) printf \'{"decision":"allow"}\\n\' ;;'); |
Summary
Fixes #4986
Augments the Antigravity CLI (
agy) agent integration to properly fire lifecycle hooks into Superset's notification system.~/.gemini/config/hooks.jsonwith a"superset-lifecycle"named entry on app start, registering all five hook events (PreInvocation,PostInvocation,PreToolUse,PostToolUse,Stop)agy-hook.shwhich maps agy event names to Superset lifecycle events (PreInvocation→Start,PostInvocation→Stop,PreToolUse→PermissionRequest,PostToolUse→Start,Stop→Stop)PreToolUse/PostToolUse) use thematcher+hooksnested format required by agy; invocation/stop hooks use the flat command formatPreToolUseresponds with{"decision":"allow"}on stdout to avoid blocking executionTest plan
~/.gemini/config/hooks.jsonis written with PascalCase keys and matcher+hooks structure for tool-use eventsagyand confirm hooks settings shows hooks as registeredPermissionRequest/Start/Stoplifecycle events from agy sessionsbun test apps/desktop/src/main/lib/agent-setup/agent-wrappers.test.ts— 39/39 passSummary by cubic
Adds desktop integration for Antigravity CLI (
agy) and connects its lifecycle hooks to Superset notifications. Installs a managed wrapper, registersagyas a built-in agent with icons, and sets up hooks under~/.gemini.New Features
~/.gemini/config/hooks.jsonwith a"superset-lifecycle"entry registeringPreInvocation,PostInvocation,PreToolUse,PostToolUse, andStop.agy-hook.shand maps events to Superset:PreInvocation→Start,PostInvocation→Stop,PreToolUse→PermissionRequest,PostToolUse→Stop,Stop→Stop.PreToolUseprints{"decision":"allow"}.matcher+hooksformat for tool-use; quotes hook paths; cleans stale/legacy Superset entries on each app start.~/.superset/bin/agythat exportsSUPERSET_AGENT_ID=agy.agytoBUILTIN_TERMINAL_AGENTSand registers preset icons for the agent picker; extends tests for the wrapper, hook script marker, andhooks.jsongeneration.Migration
agyis onPATH. Pick “Antigravity” in the agent picker; lifecycle events should appear in Superset.Written for commit 68235b8. Summary will update on new commits.
Summary by CodeRabbit
New Features
Documentation
Tests