mirror of
https://github.com/stablyai/orca.git
synced 2026-11-13 17:37:40 +00:00
* fix(antigravity): wait for agy's composer before pasting continuation context The renderer's paste gate armed its 1.5s quiet window on any bracketed-paste enable, including the launching shell's own prompt, so a slow agy start received the handoff in cooked mode before its TUI ran. Wait for agy's '? for shortcuts' composer row while agy holds bracketed paste instead. * fix(antigravity): accept agy's composer rows when a custom statusLine hides the hint A command statusLine replaces agy's '? for shortcuts' row, so Continue in New Session waited the full 20s and pasted blind, and a CLI launch prompt burned 20s of its 60s. Also accept the rule / '>' / rule composer rows (the layout #38930 reads), still anchored to agy's own 2004h and revoked by the shell's 2004l. Checked against agy 1.5.2 captures: custom statusLine and default layouts fire; the trust dialog and signed-out startup do not. * fix(antigravity): offer back pre-ready typed text the composer wait drops; move scanner tests The agy composer wait has no quiet fallback, so a slow start now hits the 20s timeout and drops held type-ahead. The drop notice now carries a Copy action with the typed text, and still shows when the user switched worktrees, so it is never lost silently. Move the composer-rows scanner cases into draft-paste-ready-scanner.test.ts since main removed antigravity-readiness-transcripts.test.ts (#38973). * chore(plugins): regenerate declarative testing bundle for antigravity config change
81 lines
3.9 KiB
TypeScript
81 lines
3.9 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { createDraftPasteReadyScanner } from './draft-paste-ready-scanner'
|
|
import { OPENCODE_AGENT_ROW_GRACE_MS } from './opencode-agent-row-scanner'
|
|
|
|
const DECSET_BRACKETED_PASTE = '\x1b[?2004h'
|
|
const DECRST_BRACKETED_PASTE = '\x1b[?2004l'
|
|
const SHOW_CURSOR = '\x1b[?25h'
|
|
const HIDE_CURSOR = '\x1b[?25l'
|
|
const ALT_SCREEN_ENTER = '\x1b[?1049h'
|
|
|
|
describe('createDraftPasteReadyScanner', () => {
|
|
describe('render-cursor-after-bracketed-paste (opencode / mimo-code)', () => {
|
|
it('never joins a show-cursor across a chunk seam from bytes it already scanned', () => {
|
|
// Why: the stream holds only a hide-cursor; re-reading carried chars used to assemble a show.
|
|
const scanner = createDraftPasteReadyScanner('render-cursor-after-bracketed-paste')
|
|
expect(scanner.observe(DECSET_BRACKETED_PASTE).ready).toBe(false)
|
|
expect(scanner.observe('Search \x1b[?25').ready).toBe(false)
|
|
expect(scanner.observe('l more text').ready).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('opencode-agent-row', () => {
|
|
// OpenCode 2.0.21 cold-start shape: row-25 box corner, then row-24 agent/model text.
|
|
const frame = (body: string): string =>
|
|
`\x1b[?2026h${HIDE_CURSOR}${body}\x1b[22;27H${SHOW_CURSOR}\x1b[?2026l`
|
|
const BOX = `${ALT_SCREEN_ENTER}${DECSET_BRACKETED_PASTE}${frame(
|
|
'\x1b[21;24H┃\x1b[22;24H┃\x1b[23;24H┃\x1b[24;24H┃\x1b[25;24H╹'
|
|
)}`
|
|
const AGENT_ROW = frame('\x1b[24;27HBuild\x1b[24;33H\u00b7\x1b[24;35HSome Model')
|
|
|
|
it('pairs a separator with a later corner only inside the same synchronized frame', () => {
|
|
const scanner = createDraftPasteReadyScanner('opencode-agent-row')
|
|
const separatorFrame = frame('\x1b[23;33H\u00b7')
|
|
const cornerFrame = frame('\x1b[24;24H╹')
|
|
expect(
|
|
scanner.observe(
|
|
`${ALT_SCREEN_ENTER}${DECSET_BRACKETED_PASTE}${separatorFrame}${cornerFrame}`
|
|
).ready
|
|
).toBe(false)
|
|
})
|
|
|
|
it('withdraws readiness and the grace timer when bracketed paste is turned off', () => {
|
|
const scanner = createDraftPasteReadyScanner('opencode-agent-row')
|
|
expect(scanner.observe(BOX + AGENT_ROW).ready).toBe(true)
|
|
expect(scanner.observe(DECRST_BRACKETED_PASTE)).toEqual({
|
|
ready: false,
|
|
armQuietTimer: false,
|
|
readyAfterMs: null
|
|
})
|
|
const graced = createDraftPasteReadyScanner('opencode-agent-row')
|
|
expect(graced.observe(BOX).readyAfterMs).toBe(OPENCODE_AGENT_ROW_GRACE_MS)
|
|
expect(graced.observe(DECRST_BRACKETED_PASTE).readyAfterMs).toBeNull()
|
|
})
|
|
})
|
|
|
|
describe('antigravity-composer-prompt', () => {
|
|
it('fires on the composer rows when a custom statusLine replaces the hint row', () => {
|
|
const rule = `\x1b[38;2;65;72;104m${'─'.repeat(80)}\x1b[m\r\n`
|
|
// agy 1.5.2 with a two-line command statusLine, after its startup splash.
|
|
const startup = `${DECSET_BRACKETED_PASTE}${ALT_SCREEN_ENTER} ⣾ Signing in...\r\ncustom-status-one\x1b[?1049l\r\n\n${rule}\x1b[38;2;122;162;247m>\x1b[m\r\n${rule}custom-status-one\r\ncustom-status-two\r\x1b[3A\x1b[2C${SHOW_CURSOR}`
|
|
expect(
|
|
createDraftPasteReadyScanner('antigravity-composer-prompt').observe(startup).ready
|
|
).toBe(true)
|
|
expect(
|
|
createDraftPasteReadyScanner('antigravity-composer-prompt').observe(
|
|
startup.replace(DECSET_BRACKETED_PASTE, '')
|
|
).ready
|
|
).toBe(false)
|
|
})
|
|
|
|
it('never arms the quiet window from the shell prompt that launches agy (#18088)', () => {
|
|
const scanner = createDraftPasteReadyScanner('antigravity-composer-prompt')
|
|
// zsh enables paste at its prompt, echoes the command, then disables paste before exec.
|
|
expect(
|
|
scanner.observe(`${DECSET_BRACKETED_PASTE}% agy '--dangerously-skip-permissions'`)
|
|
).toEqual({ ready: false, armQuietTimer: false })
|
|
expect(scanner.observe(`${DECRST_BRACKETED_PASTE}\r\r\n? for shortcuts`).ready).toBe(false)
|
|
})
|
|
})
|
|
})
|