feat: add AGY (Antigravity) harness adapter, interactive prompts, and slash commands - #99
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.
|
Thank you @AltanS Addressed your comments so please review whenever you have free minute, and feel free to reach out to me |
`locateInputBox` had a second, unanchored path: if the last non-blank row matched `/^[❯›>]\s*/` it was accepted as a live composer outright. AGY's prompt glyph is plain ASCII `>`, so that path claimed ordinary transcript rows. It is not a hypothetical shape. AGY echoes every submitted message as `> …`, and paints an answered `ask_user_question` selection the same way — both are visible in `agy--done.txt`. A markdown quote or a `git log` in the transcript reads identically. On such a screen `composerReady` answered true over a running turn and `extractInputDraft` handed the echoed line back as the operator's own draft, so a reply was authorised into a pane that could not receive it. Every capture in the corpus shows the same composer: a top rule, the `>` row, a bottom rule, then the `? for shortcuts …` status row. Path 1 already requires that box, and all three neutral fixtures resolve through it — the fallback earned nothing and is removed. A screen with no located box now fails closed, which costs a refused send instead of keystrokes into a working agent. The one unit test that depended on the fallback built its screen by hand around `"❯ "`, a glyph AGY never paints; it is rewritten on the captured boxed shape and joined by two regression tests for the unanchored rows. Fixture behaviour is unchanged: all eight agy captures keep their previous draft, status and block results. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Brings #99 (AGY / Antigravity as a first-class harness adapter: ask_question menus, permission, plan and trust dialogs lifted into native buttons, the boxed composer stripped with its status row re-surfaced, a slash-command palette and the brand icon), #132 (a large Codex send verified through `[Pasted Content N chars]`, and destructive writes bound to the whole wrapped draft), #134 + the 0.150.1 status-row work (Codex CLI 0.150.1 recognised on both of its rows, keyed on the renderer's own paint) and #130 (a forward-auth 3xx read as a 401, and Authentik's outpost paths kept out of the PWA cache) onto the v1 line. Conflicts resolved: - version trio: v1's 1.0.0-beta.32 kept; nothing else in those three files differed. - CHANGELOG: both sides kept — v1's beta entries on top, 0.36.0 in chronological place directly above 0.35.0. Nothing rewritten. - web/src/components/agent-icon-data.ts: v1's Map shape kept; main's agy and antigravity brand entries filed in it, and the source note extended to name them. - web/src/lib/agent-commands.ts: v1's Map-shaped CATALOG kept; main's AGY catalog filed under both "agy" and "antigravity", the two spellings AGENT_FAMILIES lists and canonicalAgent folds neither onto the other. - web/src/lib/api.ts: main's REDIRECT_STATUSES, normaliseProxyRedirect, apiFetch and the manual-redirect paragraph taken; v1's withScope naming kept over main's withSession. v1's fourth bridge call site, the /api/stt POST, routed through apiFetch too — it bypasses `req` like the other two and returns its refusal as a value, so a proxy 3xx has to reach it as a plain 401 as well. Every bridge call in the file now goes through apiFetch. Imported code brought up to v1's gates: codex/markers.ts scans for a C0/DEL byte by code unit instead of matching a control-character class, the way links.ts cuts the same bytes out of an href; codex.test.ts's `row` helper keeps its inferred return type rather than restating it as an anonymous object; server.test.ts's new expected_prompt case passes its fake through v1's `asMux` seam instead of main's `as unknown as HerdrClient` chain. api.test.ts gains one case for the /api/stt redirect path, which v1 owns alone. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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 #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.
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 #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
feat: add AGY (Antigravity) harness adapter, interactive prompts, and slash commands
Brings #99 (AGY / Antigravity as a first-class harness adapter: ask_question menus, permission, plan and trust dialogs lifted into native buttons, the boxed composer stripped with its status row re-surfaced, a slash-command palette and the brand icon), #132 (a large Codex send verified through `[Pasted Content N chars]`, and destructive writes bound to the whole wrapped draft), #134 + the 0.150.1 status-row work (Codex CLI 0.150.1 recognised on both of its rows, keyed on the renderer's own paint) and #130 (a forward-auth 3xx read as a 401, and Authentik's outpost paths kept out of the PWA cache) onto the v1 line. Conflicts resolved: - version trio: v1's 1.0.0-beta.32 kept; nothing else in those three files differed. - CHANGELOG: both sides kept — v1's beta entries on top, 0.36.0 in chronological place directly above 0.35.0. Nothing rewritten. - web/src/components/agent-icon-data.ts: v1's Map shape kept; main's agy and antigravity brand entries filed in it, and the source note extended to name them. - web/src/lib/agent-commands.ts: v1's Map-shaped CATALOG kept; main's AGY catalog filed under both "agy" and "antigravity", the two spellings AGENT_FAMILIES lists and canonicalAgent folds neither onto the other. - web/src/lib/api.ts: main's REDIRECT_STATUSES, normaliseProxyRedirect, apiFetch and the manual-redirect paragraph taken; v1's withScope naming kept over main's withSession. v1's fourth bridge call site, the /api/stt POST, routed through apiFetch too — it bypasses `req` like the other two and returns its refusal as a value, so a proxy 3xx has to reach it as a plain 401 as well. Every bridge call in the file now goes through apiFetch. Imported code brought up to v1's gates: codex/markers.ts scans for a C0/DEL byte by code unit instead of matching a control-character class, the way links.ts cuts the same bytes out of an href; codex.test.ts's `row` helper keeps its inferred return type rather than restating it as an anonymous object; server.test.ts's new expected_prompt case passes its fake through v1's `asMux` seam instead of main's `as unknown as HerdrClient` chain. api.test.ts gains one case for the /api/stt redirect path, which v1 owns alone. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`DEFAULT_UPDATE_REPO` is the ONE place `cli/install-kind.ts` resolves where
releases come from, and it feeds both halves of the update subject: the SOURCE
on a binary install — it selects the tags endpoint and every constructed
download URL — and the ASSERTION on the git paths. Left at `AltanS/collie` in a
fork, the phone's update banner offers upstream's release, which does not carry
the four environment patches this checkout exists to hold, and
`scripts/install.sh` fetches upstream's tarball.
So the default names this fork. The override is untouched: upstream built
`COLLIE_UPDATE_REPO` as the fork seam and it still wins, so pointing a build
back at upstream stays one variable rather than a revert.
Changed alongside it, because each names this repo's own identity rather than
citing upstream's history:
- `bridge/index.ts` — the release check behind the phone's banner.
- `scripts/install.sh` — the binary installer's default repo.
- the three `herdr plugin install <repo> --yes` recovery lines in
`cli/update.ts` and the same string in `contrib/windows/collie-ctl.ps1`:
they tell the operator how to refresh THIS install.
- two comments that name the checkout's own origin.
Deliberately NOT changed: every reference that cites upstream's history rather
than naming a code source — `CHANGELOG.md`'s hundred commit links, the `.adr/`
records, and the `AltanS#34`/`AltanS#63`/`AltanS#89`/`AltanS#99`/`AltanS#103` issue citations in `docs/`,
`PLAN_FEEDBACK_NOTES.md` and `harness/registry.ts`. Those numbers belong to
AltanS/collie and resolve to different issues here, and rewriting the changelog
would conflict on every upstream release while fixing nothing.
Tests move with the strings they pin. The origin stubs in `update.test.ts`,
`update-check.test.ts` and `doctor.test.ts` stage a checkout whose `origin`
agrees with the configured source, so they had to follow: without that, 86 cases
across five files fail on `assertOrigin` refusing before the case under test
begins.
One consequence, recorded rather than worked around: the git remote named
`origin` in this checkout is still upstream, so `collie update` now REFUSES on
the origin/source mismatch instead of silently detaching onto an upstream tag
and discarding these patches. That is the safer of the two failures and it is
the guard doing its job. Making the verb usable means naming this fork `origin`
and upstream something else.
`DEFAULT_UPDATE_REPO` is the ONE place `cli/install-kind.ts` resolves where
releases come from, and it feeds both halves of the update subject: the SOURCE
on a binary install — it selects the tags endpoint and every constructed
download URL — and the ASSERTION on the git paths. Left at `AltanS/collie` in a
fork, the phone's update banner offers upstream's release, which does not carry
the four environment patches this checkout exists to hold, and
`scripts/install.sh` fetches upstream's tarball.
So the default names this fork. The override is untouched: upstream built
`COLLIE_UPDATE_REPO` as the fork seam and it still wins, so pointing a build
back at upstream stays one variable rather than a revert.
Changed alongside it, because each names this repo's own identity rather than
citing upstream's history:
- `bridge/index.ts` — the release check behind the phone's banner.
- `scripts/install.sh` — the binary installer's default repo.
- the three `herdr plugin install <repo> --yes` recovery lines in
`cli/update.ts` and the same string in `contrib/windows/collie-ctl.ps1`:
they tell the operator how to refresh THIS install.
- two comments that name the checkout's own origin.
Deliberately NOT changed: every reference that cites upstream's history rather
than naming a code source — `CHANGELOG.md`'s hundred commit links, the `.adr/`
records, and the `AltanS#34`/`AltanS#63`/`AltanS#89`/`AltanS#99`/`AltanS#103` issue citations in `docs/`,
`PLAN_FEEDBACK_NOTES.md` and `harness/registry.ts`. Those numbers belong to
AltanS/collie and resolve to different issues here, and rewriting the changelog
would conflict on every upstream release while fixing nothing.
Tests move with the strings they pin. The origin stubs in `update.test.ts`,
`update-check.test.ts` and `doctor.test.ts` stage a checkout whose `origin`
agrees with the configured source, so they had to follow: without that, 86 cases
across five files fail on `assertOrigin` refusing before the case under test
begins.
One consequence, recorded rather than worked around: the git remote named
`origin` in this checkout is still upstream, so `collie update` now REFUSES on
the origin/source mismatch instead of silently detaching onto an upstream tag
and discarding these patches. That is the safer of the two failures and it is
the guard doing its job. Making the verb usable means naming this fork `origin`
and upstream something else.

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