v4.9.0 — mark a page by moving things and striking things out - #3
Merged
Conversation
The workspace's link state now rests on evidence a session can only produce by being there: - A stream watcher opens with a HANDSHAKE line naming a command. Its `watching` heartbeat starts when `ack` answers it, and it exits 3 after two minutes (`--handshake-timeout <seconds>`) if nothing does. - Presence also requires the rounds to move: a queued round unclaimed past 90 seconds drops the link, and `check` names it on every call. - The cog menu shows the version the workspace loaded with and the one the server is on, and offers a reload when they differ. An answer written on a comment carried in from an earlier version is kept. `postReply` and the composer's note edit copy the comment into the current version first, so the reply lands in the file the workspace reads. Stop is withdrawn to docs/review-wishlist.md, with interrupting the agent's turn as its first acceptance criterion. The `cancel` sentinel, `/api/cancel`, the `cancelled` command and the CANCELLED event go with it; `check` always exits 0. Rounds still on disk with status `cancelled` stay terminal. Host profiles move to plugins/vstack/host-profiles/, leaving `hosts/` to the adapter markdown that maps ops to a product's tools. A fitted page follows its canvas: the refit watches #stageArea, whose box no scrollbar of its own can change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…s started from A review's store sits beside the page under review, and `watch --all` found stores by walking the directory it was run from. A page written to a temp directory — where an agent puts a file it has just generated — takes its store with it, so the watcher walked straight past a running review. It then heartbeated into nothing while the workspace said Unlinked. `serve` now leaves a pointer under the directory it was run from, `.vstack/local/review/.serving/<key>`, naming the store it is serving. The watcher follows those pointers as well as walking. A pointer whose store has no `url` behind it belongs to a server that was killed, and the reader deletes it. A handshake now carries the token it printed, so only the watcher that asked acts on the answer — a second watcher's handshake is not an answer to the first. A watcher that is answered but covers no review reports UNLINKED rather than LINKED, because nothing is listening to any workspace at that point whatever the handshake proved. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…oved Two annotation tools beside Comment, on a toolbar down the left of the canvas. The bar still decides whether the pointer clicks through the page or annotates it; the toolbar decides what annotating leaves behind. It takes its own strip rather than floating over the canvas, because a toolbar in the top-left corner covers the part of a design people look at first, and it stays in both modes so switching to View and back does not move the page. Each button is an icon, so hovering one says what it is, what key picks it, and what gesture it takes: a picture of a pen does not say that clicking leaves a point and dragging leaves a box. The same three parts go to a screen reader as one sentence. Both new tools are optional-note: the mark is the instruction, and anything typed adds to it rather than supplying it. Both outline whatever the pointer is over, so the element the gesture will take is settled before the press rather than after it. Comment does not — it works on the place you press, and a box following the pointer everywhere is noise. Move draws an arrow from a thing to where it should go. A pixel delta alone stops meaning anything the first time the page reflows, so a move also captures the element it was dropped on and which side of it — inside, before, or after. The brief leads with that and keeps the delta for the case where nothing was under the drop and direction is all the reviewer gave. Delete strikes out what should go. Dragging across text takes exactly those words, through the page's own caret positions, so the agent is told the phrase to remove rather than the paragraph it sat in; the words are found again by their text when the page is rebuilt, so the strike stays on them. Clicking takes a whole element, and strikes every line written inside it — a box drawn round a paragraph leaves the words standing, which is not what was asked for. Also carries a pending one-line fix in shell.css out to every page: the [hidden] rule for the cog's version row. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two new annotation tools on a toolbar beside the page, and a watcher that finds a review whose page lives somewhere else. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
holds Comment, Move and Delete — what Annotate draws with, on keys
c,mand
d. Neither new tool needs a note: the mark is the instruction, andanything you type adds to it. Both outline whatever the pointer is over, so
the element the gesture will take is settled before you press.
element you dropped it on and which side of it — inside, before, or after —
so your agent is told "after the Cancel button" rather than "180px right",
which stops meaning anything the moment the page reflows.
words are marked for removal; the strike finds them again by their text when
the page is rebuilt, so it stays on them. Click an element instead and the
whole thing is marked.
started from. A review's files sit beside the page under review, and
watch --allfound them by walking the directory it ran in. A page written toa temp directory took its files with it, so the watcher walked straight past a
running review and the workspace said Unlinked while a session was in fact
listening. Serving now leaves a pointer where it was run from, and the watcher
follows it.
UNLINKEDinstead ofLINKED, because nothing is listening to any workspace at that point whateverthe handshake proved. A handshake also carries the token it printed, so one
watcher's answer no longer brings a different watcher live.