mirror of
https://github.com/stablyai/orca.git
synced 2026-09-21 16:02:20 +00:00
* test(runtime): capture real agent PTY transcripts before rewriting Antigravity readiness
Antigravity readiness has been written five times against a five-line screen
typed from memory. There is no Antigravity transcript in this repository, so
every attempt was a guess tested against another guess. This adds the recorder,
the protocol and the fixture-driven suite so the sixth attempt can be written
against evidence, and changes no detector logic.
- config/scripts/capture-agent-pty-transcript.mjs records a live agent session
through a real PTY, escapes and wrapping intact. Ctrl-] is consumed by the
recorder and never forwarded, which is the only way to end a capture while a
dialog still owns the screen.
- config/scripts/pty-transcript-secret-scan.mjs finds account identifiers and
credentials, redacts them with same-length placeholders so wrapping survives,
and recognises its own placeholders so a scrubbed file verifies clean.
- src/main/runtime/antigravity-readiness-transcripts.test.ts asserts a verdict
per transcript and skips by name until the transcripts land, with a
doc-coverage ratchet and a guard that a fixture contains escape bytes.
The escape-byte guard exists because the three cursor-agent fixtures carry a
comment claiming they were captured verbatim through Orca, yet contain zero ESC
bytes and zero carriage returns. That comment is corrected here to say what
those files are; the fixtures and the rules built on them are untouched.
* test(runtime): capture real Antigravity transcripts, and pin what they prove
`agy` 1.1.25 turned out to be installed, so the transcripts this scaffold was
built for now exist. Six are recorded from live sessions and committed; the
rest are named as skipped, because reaching them would mean signing the
operator out or deleting their config.
The captures invert the story. On real output the shipped detector refuses a
genuinely ready screen and accepts a live `/model` picker:
- Antigravity paints a block-glyph logo down the left, so the model row never
starts a line. `startsWith('gemini', trimmedStart)` cannot match a real ready
screen, on any account or model. Stripping the logo flips the same screen to
ready, which means a decorative glyph decides readiness today.
- The `/model` picker prints `Gemini 3.x Flash` one per line, at line start, and
a bare `>` composer sits earlier in the tail. Both halves of the rule are
satisfied while a dialog owns the screen.
- For an API-key user the identity row reads `Gemini API key` — no `@`, no
domain — and `AGY_CLI_HIDE_ACCOUNT_INFO=1` removes the row entirely. The
account-row requirement of attempts 4 and 5 can never pass for those users.
- The banner is printed once and never reprinted after a dialog is dismissed, so
`headerIndex` cannot be the ordering anchor.
Four suite cases are pinned as KNOWN DEFECT: they assert what the detector does
so CI stays honest instead of permanently red, and flip to failing the moment
someone fixes it. No detector logic changed.
The recorder gains `--send "<ms>:<text>"` because a dialog capture has to be
driven and an unattended run has no TTY, and the scrub scanner gains a UUID rule
because agy prints a resumable conversation id on exit.
* test(runtime): capture agy mid-turn, and make the scan file reviewable
Answers the busy-frame question a P1 review raised against attempt six, with
two new captures from a live turn.
At the frame level the review is right: a busy frame parks the caret with the
same bytes as an idle one, `CR ESC[2A ESC[2C`, and the only differing row —
`esc to cancel` versus `? for shortcuts` — is erased by that park.
At the retained-tail level it does not reproduce. Each spinner tick is its own
repaint with its own `CR ESC[2A`, two rows higher than the frame's, which
splices the composer away: a live turn's tail ends on `⣟ Generating...`, with
no bare caret to match. A constructed input that keeps the park and edits only
the status text is not faithful, because a live turn has a spinner row
repainting below the composer.
The residual is the gap between a frame park and the next tick, where the tail
does end on the bare caret. Quiescence-gated paths are safe there because ticks
keep arriving; text-only paths are not, and for those the capture supports one
clause: a braille glyph on the last visible line means working. That predicate
already exists here for cursor-agent and should be reused, scoped to the last
line — a first-run transcript prints `⠾ Signing in...` during startup.
Also in this commit, from the same review:
- pty-transcript-secret-scan.mjs held raw 0x00-0x1f bytes in a character class,
so the one file gating real PTY data into history was binary to git and
unreviewable in a diff. It now tests codepoints, which the formatter cannot
fold back into control bytes.
- Pin `src/main/runtime/__fixtures__/*.txt` as -text. A Windows checkout would
otherwise normalise line endings and rewrite the CR bytes that make these
files evidence.
The recorder now stops appending at the stop moment rather than through
shutdown: an agent repaints an idle frame on its way out, which was overwriting
the mid-turn state the capture existed to record.
* test(tooling): allowlist the transcript scan test in the batch-shim ratchet
pty-transcript-secret-scan.test.mjs asserts that the capture recorder routes
an 'agy.cmd' shim through cmd.exe, so the shim literal it names is the
assertion, not a spawn. Fits the existing assert-on-shim-files category.
44 lines
2.8 KiB
Plaintext
44 lines
2.8 KiB
Plaintext
# A shebang plus CRLF makes vite's SSR transform emit a literal `#!` mid-module,
|
|
# so any suite importing the script dies at load with a SyntaxError. Pin the whole
|
|
# directory rather than the scripts that happen to have a test today.
|
|
/config/scripts/**/*.mjs text eol=lf
|
|
/skill-guides/*.md text eol=lf
|
|
/skill-stubs/*.md text eol=lf
|
|
/skill-stubs/_shared/*.md text eol=lf
|
|
/skills/*/SKILL.md text eol=lf
|
|
/src/cli/bundled-skill-guides.ts text eol=lf
|
|
# Bundled plugin trees are byte-hashed; CRLF checkout would break the pinned hash.
|
|
/resources/plugins/** text eol=lf
|
|
# Relay assets are copied verbatim into the bundle and hashed byte-for-byte into
|
|
# .version, which names the immutable remote install dir. A CRLF checkout makes a
|
|
# Windows-built client disagree with a mac/Linux-built one on the same release,
|
|
# so one host ends up with two relay trees (#17886 review).
|
|
/config/relay-assets/** text eol=lf
|
|
# Pin the bytes so a patch reads and diffs identically on every host. It is NOT
|
|
# what makes the hash right: pnpm hashes a patch LF-normalized, so a CRLF checkout
|
|
# cannot change it. Believing otherwise put a hand-computed raw digest in the
|
|
# lockfile twice and broke every install (#17886).
|
|
# These files are stored LF, which is not always the encoding they were written
|
|
# against -- @vscode/windows-process-tree ships CRLF sources -- so any code that
|
|
# runs `git apply` on one must force `-c core.autocrlf=input` rather than trust
|
|
# the host's setting. See config/scripts/windows-process-tree-gyp-rebuild.mjs.
|
|
/config/patches/*.patch -text
|
|
# The xterm bundle hunks also make a diff nobody can read; review the hand-written
|
|
# source patch under xterm-src/ instead. The sibling patches stay diffable.
|
|
/config/patches/@xterm__xterm@*.patch -diff
|
|
/config/patches/xterm-src/*.patch text eol=lf
|
|
# Generated wrapper fixtures: collapse them in the PR diff so they stop drowning
|
|
# the reviewable change, and pin LF because they are compared byte-for-byte.
|
|
# Not -diff: the shell diff is the review surface when a wrapper does change.
|
|
/src/main/__fixtures__/shell-wrapper-snapshots/*.txt linguist-generated=true text eol=lf
|
|
# Captured agent PTY transcripts. -text, not `text eol=lf` like the wrapper snapshots above:
|
|
# these carry real CR and CRLF bytes as the terminal emitted them, and line-ending
|
|
# normalisation on a Windows checkout would rewrite the evidence the fixture exists to be.
|
|
/src/main/runtime/__fixtures__/*.txt -text
|
|
# Generated runtime English subset: compared byte-for-byte by
|
|
# verify:localization-runtime-catalog, so a CRLF checkout would fail the gate.
|
|
/src/renderer/src/i18n/en-runtime-required.json linguist-generated=true text eol=lf
|
|
# Generated method->params catalog: compared byte-for-byte by
|
|
# verify:rpc-params-catalog, so a CRLF checkout would fail the gate.
|
|
/src/shared/rpc-contract/rpc-params-catalog.generated.ts linguist-generated=true text eol=lf
|