feat: add AGY (Antigravity) harness adapter, interactive prompts, and slash commands - #99
feat: add AGY (Antigravity) harness adapter, interactive prompts, and slash commands#99Kryvonis wants to merge 6 commits into
Conversation
|
Thanks — the agy work is welcome. The command catalog and the icon are fine as they are. The adapter emits Two changes I'd want regardless:
Bring the corpus + notes + conformance and run the live check on your session, and I'll take it whole. |
agy's first drop emitted prompt-select (Tier 2, live keystrokes) and prefix-matched inside adapterFor. Stay Tier 1, register agent "grok" exactly, and keep catalog folding in canonicalAgent. ADR 0009 still blocks digit synthesis if a later dialog lift lands.
rstrip not peel (same helper as omp/claude). Bottom-border capture uses [\s\S] so U+2028 cannot silently decline a frame. Cite AltanS#99 the way the rest of the repo cites issues. Revert the 0.33.0 bump — CLAUDE.md: a fork PR leaves version and CHANGELOG to the maintainer.
Grok Build panes get the Claude-level treatment: stripped composer chrome with an opaque status strip, native buttons for the probed dialogs, a journal adapter, and a slash-command palette. Registered by exact agent string only (the AltanS#99 bar): adapterFor stays Object.hasOwn over adapter.agent; grok-build catalog folding lives in canonicalAgent. Every keystroke the adapter emits comes from a dated live probe recorded in the notes files, against a byte-faithful fixture corpus, with describeAdapterConformance running grok against the claude and omp cohorts and vice versa. Chrome (Tier 1): the rounded composer box is located by its bottom status border and stripped; the status run is opaque across models and efforts. composerReady gates the reply path. The startup screen's bare [stable] telemetry chip under the box is chrome (matched literally — any other bracket tag is torn transcript and refuses), so a fresh pane accepts its first message. Grok paints background across fully blank rows, which striped the mirror; empty rows lose their paint — no colour inference — while glyph rows keep every background they drew. Permission cards: classified, not layout-pinned. The footer must name the family and count its rows (1/N:select), the last row must be the reject, the row above it the one-shot Yes, and every earlier row must prove itself a persistent mode change — those never become buttons. Unrecognized control rows, or text below the options, refuse the whole card. Both live layouts (3-option rm, 4-option edit) lift to Yes/No. ask_user_question: radio cards lift with digit keys; the z free-text row is modelled as feedback (purpose "free-text" — Collie never types into it) and locks the buttons whenever the keyboard sits on it, which the inner hint row's Enter:edit verb reveals even when the row repaints idle (the hint is matched as a whole anchored row, never as a substring of prose). Esc-parked cards send Tab (the footer's own key) before the digit — a bare digit is swallowed in scrollback. Checkbox cards stay raw: a digit submits rather than toggles. Multi-question wizards step through as consecutive lifted cards. Plan approval: a menu of footer-named keys only (ADR 0009 — no digits), with the composer gated while the review is up. Dialogs replace the screen from their first option row down, so the question stays in the raw mirror above the buttons — the same contract as Claude's prompt-select. The dialog signature spans the whole card; the bridge race guard refuses a stale press (409) after the screen moves. Journal: bridge/journal/grok.ts reads chat_history.jsonl from $GROK_HOME (override: COLLIE_GROK_ROOT) via containedRealpath, refusing non-UUID refs. journal-probe verifies every populated root separately — one healthy root never vouches for a broken sibling. Neutral-model changes riding along: PromptFeedback.purpose (free-text rows render no feedback composer and submitPromptFeedback refuses them), and PromptOption.keyLabel (the badge shows the digit when a recovery key precedes it). /auto joins the dangerous two-tap set — it changes approval behavior. Claude behavior unchanged, pinned by the existing claude suites. Versions untouched per the fork-PR rule; CHANGELOG line in the PR body. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PFH7jQVDVhPGC6FqLetNfd
Codex panes get the Claude-level treatment: the boxless chrome stripped and re-surfaced natively, plus native buttons for the three probed dialogs. Registered by exact agent string only (the AltanS#99 bar): adapterFor stays Object.hasOwn over adapter.agent; variant spellings stay raw. Every keystroke the adapter emits comes from a dated live probe recorded in the notes files, against a byte-faithful fixture corpus (identifying strings length-preservingly genericized — public repo), with describeAdapterConformance running codex against the claude and omp cohorts and vice versa. Chrome (Tier 1): Codex paints a bare `› ` prompt row that word-wraps onto indented continuation rows, a dot-separated status row beneath, and exactly one blank row between every section. The composer is located by the status row at the tail (the ` · Context N% left` token; everything before it is opaque — models and paths change) with the prompt row above it — a transcript echo of a submitted message paints the same `› ` prefix and never has the status row beneath it. The status row feeds the strip, the prompt row the draft (wrapped drafts rejoin with single spaces, verified against the typed original) and composerPrompt. Trust prompt: the exact captured two-option layout lifts as family trust. Digits confirm directly — 2 quit on the spot, 1 accepted through the guarded send path (both probed). Exec approval: classified, not layout-pinned — the first row must be the one-shot Yes, the last the reject, and every row between must prove itself persistent (`don't ask again …`); those never become buttons. An unclassified row refuses the whole card. Digits confirm directly: 1 ran the approved command, 3 rejected it with the command verified never run. The header, Reason and `$ command` rows stay in the raw mirror above the buttons. Only the exec approval is captured; other approval kinds fail closed until probed. Note the config dependency: approvals_reviewer = "auto_review" (the host default here) approves silently and the dialog never paints — probing used `-c approvals_reviewer=user`. request_user_input: the Question X/Y card lifts as family select, one digit per row — a digit answers the current question, advances a multi-question set, and submits on the last (all probed). The notes-box state refuses to raw (footer `tab or esc to clear notes`, or the `› Add notes` row): a digit there would type into the box. Esc interrupts the whole conversation and is never emitted. Live-verified end to end through the bridge on a real pane: trust accepted, a reply typed-verified-submitted through the new draft extraction, an approval Yes landing its command, and an ask answer registering in the tool result — every press through the guarded /keys endpoint with its region signature. Versions untouched per the fork-PR rule; CHANGELOG line in the PR body. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PFH7jQVDVhPGC6FqLetNfd
Grok Build panes get the Claude-level treatment: stripped composer chrome with an opaque status strip, native buttons for the probed dialogs, a journal adapter, and a slash-command palette. Registered by exact agent string only (the AltanS#99 bar): adapterFor stays Object.hasOwn over adapter.agent; grok-build catalog folding lives in canonicalAgent. Every keystroke the adapter emits comes from a dated live probe recorded in the notes files, against a byte-faithful fixture corpus, with describeAdapterConformance running grok against the claude and omp cohorts and vice versa. Chrome (Tier 1): the rounded composer box is located by its bottom status border and stripped; the status run is opaque across models and efforts. composerReady gates the reply path. The startup screen's bare [stable] telemetry chip under the box is chrome (matched literally — any other bracket tag is torn transcript and refuses), so a fresh pane accepts its first message. Grok paints background across fully blank rows, which striped the mirror; empty rows lose their paint — no colour inference — while glyph rows keep every background they drew. Permission cards: classified, not layout-pinned. The footer must name the family and count its rows (1/N:select), the last row must be the reject, the row above it the one-shot Yes, and every earlier row must prove itself a persistent mode change — those never become buttons. Unrecognized control rows, or text below the options, refuse the whole card. Both live layouts (3-option rm, 4-option edit) lift to Yes/No. ask_user_question: radio cards lift with digit keys; the z free-text row is modelled as feedback (purpose "free-text" — Collie never types into it) and locks the buttons whenever the keyboard sits on it, which the inner hint row's Enter:edit verb reveals even when the row repaints idle (the hint is matched as a whole anchored row, never as a substring of prose). Esc-parked cards send Tab (the footer's own key) before the digit — a bare digit is swallowed in scrollback. Checkbox cards stay raw: a digit submits rather than toggles. Multi-question wizards step through as consecutive lifted cards. Plan approval: a menu of footer-named keys only (ADR 0009 — no digits), with the composer gated while the review is up. Dialogs replace the screen from their first option row down, so the question stays in the raw mirror above the buttons — the same contract as Claude's prompt-select. The dialog signature spans the whole card; the bridge race guard refuses a stale press (409) after the screen moves. Journal: bridge/journal/grok.ts reads chat_history.jsonl from $GROK_HOME (override: COLLIE_GROK_ROOT) via containedRealpath, refusing non-UUID refs. Neutral-model changes riding along: PromptFeedback.purpose (free-text rows render no feedback composer and submitPromptFeedback refuses them), and PromptOption.keyLabel (the badge shows the digit when a recovery key precedes it). /auto joins the dangerous two-tap set — it changes approval behavior. Claude behavior unchanged, pinned by the existing claude suites. Versions untouched per the fork-PR rule; CHANGELOG line in the PR body.
|
Both asks are addressed — 1. The fixtures aren't captures. Every file in the corpus is a byte-faithful This is the one that blocks the rest: the keystroke table in 2. Collie would paint that as the operator's draft. 3. Please restore the completeness gate in Claude's Two notes, not conditions. Bring the real captures and the chrome fix and I'll take it. |
Codex panes get the Claude-level treatment: the boxless chrome stripped and re-surfaced natively, plus native buttons for the three probed dialogs. Registered by exact agent string only (the AltanS#99 bar): adapterFor stays Object.hasOwn over adapter.agent; variant spellings stay raw. Every keystroke the adapter emits comes from a dated live probe recorded in the notes files, against a byte-faithful fixture corpus (identifying strings length-preservingly genericized — public repo), with describeAdapterConformance running codex against the claude and omp cohorts and vice versa. Chrome (Tier 1): Codex paints a bare `› ` prompt row that word-wraps onto indented continuation rows, a dot-separated status row beneath, and exactly one blank row between every section. The composer is located by the status row at the tail (the ` · Context N% left` token; everything before it is opaque — models and paths change) with the prompt row above it — a transcript echo of a submitted message paints the same `› ` prefix and never has the status row beneath it. The status row feeds the strip, the prompt row the draft (wrapped drafts rejoin with single spaces, verified against the typed original) and composerPrompt. Trust prompt: the exact captured two-option layout lifts as family trust. Digits confirm directly — 2 quit on the spot, 1 accepted through the guarded send path (both probed). Exec approval: classified, not layout-pinned — the first row must be the one-shot Yes, the last the reject, and every row between must prove itself persistent (`don't ask again …`); those never become buttons. An unclassified row refuses the whole card. Digits confirm directly: 1 ran the approved command, 3 rejected it with the command verified never run. The header, Reason and `$ command` rows stay in the raw mirror above the buttons. Only the exec approval is captured; other approval kinds fail closed until probed. Note the config dependency: approvals_reviewer = "auto_review" (the host default here) approves silently and the dialog never paints — probing used `-c approvals_reviewer=user`. request_user_input: the Question X/Y card lifts as family select, one digit per row — a digit answers the current question, advances a multi-question set, and submits on the last (all probed). The notes-box state refuses to raw (footer `tab or esc to clear notes`, or the `› Add notes` row): a digit there would type into the box. Esc interrupts the whole conversation and is never emitted. Live-verified end to end through the bridge on a real pane: trust accepted, a reply typed-verified-submitted through the new draft extraction, an approval Yes landing its command, and an ask answer registering in the tool result — every press through the guarded /keys endpoint with its region signature. Versions untouched per the fork-PR rule; CHANGELOG line in the PR body. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PFH7jQVDVhPGC6FqLetNfd (cherry picked from commit e5fab3a)
Grok Build panes get the Claude-level treatment: stripped composer chrome with an opaque status strip, native buttons for the probed dialogs, a journal adapter, and a slash-command palette. Registered by exact agent string only (the AltanS#99 bar): adapterFor stays Object.hasOwn over adapter.agent; grok-build catalog folding lives in canonicalAgent. Every keystroke the adapter emits comes from a dated live probe recorded in the notes files, against a byte-faithful fixture corpus, with describeAdapterConformance running grok against the claude and omp cohorts and vice versa. Chrome (Tier 1): the rounded composer box is located by its bottom status border and stripped; the status run is opaque across models and efforts. composerReady gates the reply path. The startup screen's bare [stable] telemetry chip under the box is chrome (matched literally — any other bracket tag is torn transcript and refuses), so a fresh pane accepts its first message. Grok paints background across fully blank rows, which striped the mirror; empty rows lose their paint — no colour inference — while glyph rows keep every background they drew. Permission cards: classified, not layout-pinned. The footer must name the family and count its rows (1/N:select), the last row must be the reject, the row above it the one-shot Yes, and every earlier row must prove itself a persistent mode change — those never become buttons. Unrecognized control rows, or text below the options, refuse the whole card. Both live layouts (3-option rm, 4-option edit) lift to Yes/No. ask_user_question: radio cards lift with digit keys; the z free-text row is modelled as feedback (purpose "free-text" — Collie never types into it) and locks the buttons whenever the keyboard sits on it, which the inner hint row's Enter:edit verb reveals even when the row repaints idle (the hint is matched as a whole anchored row, never as a substring of prose). Esc-parked cards send Tab (the footer's own key) before the digit — a bare digit is swallowed in scrollback. Checkbox cards stay raw: a digit submits rather than toggles. Multi-question wizards step through as consecutive lifted cards. Plan approval: a menu of footer-named keys only (ADR 0009 — no digits), with the composer gated while the review is up. Dialogs replace the screen from their first option row down, so the question stays in the raw mirror above the buttons — the same contract as Claude's prompt-select. The dialog signature spans the whole card; the bridge race guard refuses a stale press (409) after the screen moves. Journal: bridge/journal/grok.ts reads chat_history.jsonl from $GROK_HOME (override: COLLIE_GROK_ROOT) via containedRealpath, refusing non-UUID refs. Neutral-model changes riding along: PromptFeedback.purpose (free-text rows render no feedback composer and submitPromptFeedback refuses them), and PromptOption.keyLabel (the badge shows the digit when a recovery key precedes it). /auto joins the dangerous two-tap set — it changes approval behavior. Claude behavior unchanged, pinned by the existing claude suites. Versions untouched per the fork-PR rule; CHANGELOG line in the PR body.
Summary
Adds support for AGY (Google Antigravity CLI /
agy/antigravity) to Collie:Interactive Prompt Up-Leveling (
web/src/lib/harness/agy/):ask_questiondialogs, numbered options (1. Option,1) Option,[1] Option,( ) 1.Option), and permission/confirmation prompts into native tappable buttons.composerReady).[digit, "Enter"]or[digit]).Slash Command Palette (
web/src/lib/agent-commands.ts):agy,agy-cli, andantigravity:/plan,/grill-me,/learn,/compact,/clear,/model,/status,/subagents,/skills,/rules,/mcp,/hooks,/review,/diff,/doctor,/theme,/help,/exit.Brand Styling & Icon (
web/src/components/agent-icon*):#1A73E8) foragyandantigravitypane badges and switcher tiles.Registry & Case/Prefix Normalization (
web/src/lib/harness/registry.ts):adapterForto support casing and common prefix variants (agy,agy-cli,antigravity).Suggested CHANGELOG Entry
AGY (Antigravity CLI) gets a harness adapter — up-levels interactive question options (
ask_question) and tool permission dialogs into tappable buttons, gates the composer against typing into active menus, adds the AGY slash command palette, and includes brand icons.Verification