Repository navigation
feat(harness): add pi harness adapter and interactive dialog lifting - #397
raffaelenatale wants to merge 2 commits into
Conversation
988a6d9 to
4853460
Compare
6682a25 to
4807498
Compare
…hook Two harness-neutral capabilities a dialog grammar can opt into: - MultiSelectModel gains the `walkSpace` toggle recipe: Up/Down walk the pointer onto the target row, a fresh read verifies it landed, then Space toggles it, bound to that read (ADR 0080). The optional `advanceNeedsChecked` flag disables the card's advance button and refuses the advance unless at least one option is checked and the pointer rests on an option row; the keys path re-checks it on a fresh read before writing. - HarnessAdapter gains the optional `dialogAcceptsTyping` probe. When it answers true for the lifted dialog on screen, the composer sends through the normal type-then-verify path instead of the AltanS#34 "a dialog is waiting" refusal; the composerReady pre-flight still runs. Absent or false, the refusal stands as before. - WizardModel gains optional `submitAction` and `submitLabel` on review phase, and single-choice dialog cards support `customInput` action focusing the mobile composer with an answer-specific placeholder.
Tier 1 chrome stripping plus Tier 2 dialog lifts for pi 1.1.0 with the pi
question extension:
- `composer.ts`: frame-anchored scanner at the buffer tail. Strips top and
bottom horizontal rules (`─{8,}`), user draft, slash palette, and bounded
footer (1..4 rows, default 2-row cwd+stats or custom extension powerbar).
Extracts draft and statuslines; bounds `composerPrompt` within the 6-row
bridge tail window.
- `frame.ts`: tail-anchored detection of dialog frames bounded by matching
accent rules, identifying question body, key-hint footer (`Esc to cancel`),
and questionnaire tab bar (`← ▢ Q1 ▣ Q2 ✓ Review →`). Resilient to
terminal resize redraw artifacts.
- `question.ts`: lifts standalone single-select questions into PromptSelectBlock
(`prompt-select`, family "select") with digit plans `["N", "Enter"]`, and
`customInput` / `customAnswer` detection.
- `multi.ts`: lifts standalone and questionnaire multi-select pages into
MultiSelectBlock (`multi-select`, phase "checkbox") with `walkSpace`
toggles, `advanceKeys: ["Enter"]`, and `advanceNeedsChecked: true`.
- `tabs.ts`: lifts questionnaire single pages and review into WizardBlock
(`wizard`), with digit selection on question pages and Enter submit on
Review, setting `submitAction: "goToFirstUnanswered"` when incomplete.
- `answer-editor.ts`: reads inline free-answer editor (`newlineSubmits: true`).
- `modal.ts`: positive evidence for unread dialog card (`cancelKey: "Escape"`).
- `index.ts`: `newlineSubmits` answers true on active dialog pages to reject
multiline sends in preflight; `dialogAcceptsTyping` answers false on multi-select.
- Verified versions ledger entry updated for pi 1.1.0 (`how: "canary"`).
- Canary runner: fixes readers liveness freshening during reader invocations.
- Fixtures and test suite covering Tier 1 chrome and lifted dialog variants.
4807498 to
7c52e44
Compare
The canary transport never stamped lib/liveness.ts after a pane read, so the M46 isLive gate in sendGuardedReply refused every canary send. The transport now reports each 200 or 304 read, and run.ts hands that to the readers' markLive, as the client's fetchPane does. An older --readers checkout without a liveness module is left alone. Extracted from PR #397 by @raffaelenatale, harness-canary hunks only. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Thanks @raffaelenatale, one part of this lands in 1.19.2 and the rest waits. The harness-canary change that stamps a pane live after each read is in, extracted as its own commit under your name, since the M46 gate had been refusing every canary send. The pi screen adapter and the dialog lifts are held. The dialog grammar reads an extension I cannot identify: the strings match neither pi's own question examples nor |
|
Thanks @raffaelenatale, part of this lands in 1.20.1 and I am closing the PR. Your captures and three composer facts are in, with you as co-author on the commit and named in the changelog. Instead of a grammar for your extension, one reader now serves every pi question screen by its shape and the keys its footer names; against your captures it gives buttons for single questions, tab pages and a complete Review page, but I could not run your extension live, so please confirm on your setup. The shared |
Overview
This PR adds a harness adapter for Pi (
pi-coding-agent,agent: "pi") covering both Tier 1 chrome parsing and Tier 2 interactive dialog lifting.It lifts single-select options, questionnaire multi-step tabs and review screens, multi-select dialogs, and the inline free-answer editor into native tappable buttons on mobile, while keeping full fail-closed bounds and supporting unread modal escape via positive footer evidence.
It also introduces two harness-neutral infrastructure additions:
walkSpacemulti-select toggle choreography (with opt-inadvanceNeedsCheckedflag).dialogAcceptsTypingadapter probe allowing mobile composer input while an interactive dialog is active on screen.1. Core Harness Infrastructure
walkSpaceChoreography (web/src/lib/harness/multi-select-model.ts,web/src/lib/multi-select-action.ts):Navigates arrow keys directly onto the pointed row based on the fresh terminal read from
guardDialog, verifies pointer settlement on a fresh re-read, and sendsSpacewithoutEnter. Multi-select models are decoupled fromWALK_PAIRS(which remain prompt-select only).advanceNeedsCheckedopt-in:Enforces that the advance/confirm button is disabled when zero options are checked or when the pointer rests on non-option rows.
dialogAcceptsTypinghook (web/src/lib/harness/types.ts,web/src/components/composer.tsx,web/src/components/agent-chat.tsx):Allows adapters whose dialogs support custom keyboard answers (such as Pi's
questiontool) to keep the mobile composer enabled while a lifted card is displayed, routing typed text through type-then-verify without relaxing safety check PWA send renders in the pane's input box but never reaches the input buffer (silently lost) #34 for other harnesses.customInputAction & Composer Pre-fill:Dialogs offering free-form input ("Type something.") render a dedicated action button (
Type a custom answer below…) that focuses the mobile composer with an answer-specific placeholder (Type an answer…). When a custom answer is already recorded, the button reflects it (Custom answer: … ✓) and populates the composer on tap for in-place editing.submitActionIntent:WizardModelreview phase supports an explicitsubmitActionintent ("submit"|"goToFirstUnanswered"). On incomplete Review screens where Enter only jumps to the next unanswered question (as in Pi), the button accurately communicatesGo to first unanswered questioninstead of misleadingly offering to submit incomplete answers, while leaving Claude and OpenCode review buttons untouched asSubmit answers.2. Pi Harness Adapter (
agent: "pi")composer.ts: pureStyledLine[]scanner recognizing Pi's horizontal border frame (─{8,}), statusline tail, slash palette, and nested rules inside multiline drafts.modal.ts: positive evidence probe (modalOnScreen) for Pi core modal selectors (such as/modelor/theme), arming the unread-dialog card withcancelKey: "Escape".answer-editor.ts: inline free-answer editor reader and prompt binding (newlineSubmits: true).question.ts: standalone single-choice dialogs lifted toprompt-selectwith numeric key bindings (["1", "Enter"]...["9", "Enter"]), andcustomInput/customAnswerdetection.tabs.ts: questionnaire tab bar navigation (← □ Q1 ... ■ Q2 ... ✓ Submit →) and Review screen lifting intowizard, settingsubmitAction: "goToFirstUnanswered"when incomplete.multi.ts: multi-select checkbox lists ([ ]/[x]) withwalkSpacetoggle, supporting bothSpace to tickandSpace to togglefooter conventions (@juicesharp/rpiv-ask-user-questionparity).frame.ts: resilient to transient terminal resize redraw artifacts (duplicate border rules and interim spinner rows).index.ts:newlineSubmitsanswers true on all active dialog pages so multiline drafts typed on the phone are refused in preflight before sending raw newlines that would select an option underfoot.Evidence & Verification
Captured in
web/src/fixtures/panes/pi--v110-*.txtand documented inweb/src/fixtures/panes/README.md, covering idle composers, statuslines, single questions, questionnaire tabs, multi-select toggles, and review screens. Verified viacorpus.test.ts.bun run canary --agent pipasses all 6 scenarios (idle,drafts,sends,journal,narrow,start-exit). Stamped inweb/src/lib/harness/verified-versions.json(how: "canary").Updated
scripts/harness-canary/readers.tsandtransport.tsto freshen pane liveness on successful reads (M46 parity).Verified against a live Pi instance driven by mobile Chromium on Xvfb (402×874 viewport) and real mobile hardware:
["1", "Enter"]plan) submitted and settled immediately.Space(walkSpace) verified with disabled confirm button at 0 ticks.dialogAcceptsTypingvalidated with typed custom answer submitted while dialog was visible./modelselector dismissed cleanly with 2-tapEscapecard.bun run typecheck&cd web && bun run typecheck→ 0 errors.oxlint --max-warnings 0(including vendoredanti-slopplugin rules) → 0 warnings, 0 errors.cd web && bunx vitest run→ 386 files, 22,828 tests passed.bun test ./bridge ./cli ./scripts→ all passed.scripts/check-version.sh→ clean (v1.19.1 consistent).Base branch
mainChecks
bun run typecheck(root andweb/),bun run lint,bun test ./bridge ./cli ./scripts,cd web && bun run testall passCHANGELOG entry for the release
Per CONTRIBUTING (fork PRs leave version files and CHANGELOG untouched), entry for maintainer to place under
## [Unreleased]→### Added:pi-coding-agent). Lifts Pi's interactive question tool dialogs (single-select options, questionnaire tabs, Review screen, and multi-select checkboxes) into native tappable mobile buttons. AddswalkSpacemulti-select choreography and thedialogAcceptsTypingadapter probe. (fixtures:web/src/fixtures/panes/pi--v110-*.txt, notes:web/src/lib/harness/pi/PI_NOTES.md)