Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ jobs:
- name: Restored agents start one at a time
if: runner.os == 'Windows'
run: node qa/restore-pacing.mjs
- name: Images tied to their terminal rows
if: runner.os == 'Windows'
run: node qa/image-rows.mjs
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
if: always()
with:
Expand All @@ -141,4 +144,5 @@ jobs:
qa/shots/perf-gate/
qa/shots/images/
qa/shots/images-remote/
qa/shots/image-rows/
qa/shots/claude-update/
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ See what needs attention, resume the right conversation, and work on a paired PC

</div>

> **1.39.0** shows the screenshots and images a Claude session worked with — Claude Desktop shows them inline; DevDeck puts them in a strip beside the terminal, also for sessions on another PC — adds 📎 / drag-and-drop attachments (images travel to a remote PC), **Update all** for Claude Code on Windows, staggered session restores that no longer stall a PC, and ends the daily false "Login expired" ([release notes](docs/releases/1.39.0.md)). 1.38.0 made closing a session reliable across paired PCs ([notes](docs/releases/1.38.0.md)). See [the maintenance review](docs/quality-review-2026-09-08.md) and [session synchronization review](docs/session-sync-review-2026-09-08.md).
> **1.40.0** ties each screenshot to the terminal row it appeared on — hover a highlighted `[Image]` for a thumbnail, click for the full view, and jump from the viewer back to the row — says what led to each image, previews new screenshots, copies images, and adds Ctrl+↑/↓ between your prompts ([release notes](docs/releases/1.40.0.md)). 1.39.0 shows the screenshots and images a Claude session worked with — Claude Desktop shows them inline; DevDeck puts them in a strip beside the terminal, also for sessions on another PC — adds 📎 / drag-and-drop attachments (images travel to a remote PC), **Update all** for Claude Code on Windows, staggered session restores that no longer stall a PC, and ends the daily false "Login expired" ([release notes](docs/releases/1.39.0.md)). 1.38.0 made closing a session reliable across paired PCs ([notes](docs/releases/1.38.0.md)). See [the maintenance review](docs/quality-review-2026-09-08.md) and [session synchronization review](docs/session-sync-review-2026-09-08.md).

<div align="center">
<img src="docs/screenshots/projects.png" width="820" alt="DevDeck project overview with repository and session navigation" />
Expand Down
2 changes: 1 addition & 1 deletion docs/quality.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Results and screenshots are written to `qa/shots/maintenance/` and `qa/shots/res

The CI performance gate is `qa:perf-gate` (Windows, every push): a fixture agent instead of a real one, and units that do not depend on the runner's speed — running CSS animations and DOM mutation records on an idle deck (both must be ~0), DOM mutations outside the terminals while two tiles repaint at 10fps (a per-chunk sidebar rebuild is ~8,000 against a limit of 400), and the main process's longest event-loop stall while working and while 20,000 lines stream. Each limit was checked by injecting the regression it guards against: an infinite CSS animation, a sidebar render per PTY chunk, and a 700ms synchronous block in the main process all fail it. Results go to `qa/shots/perf-gate/results.json`.

`qa:images` (Windows) drives the cockpit image strip, full-size viewer and 📎 attach against an isolated home holding a transcript with a tool screenshot, a pasted image and a written image file; its fixture `claude` echoes what it is sent, so an attached path is read back off the terminal. `qa:update` (Windows) checks "Update all": a fixture `claude` prints Claude Code's failed-update footer, and the harness asserts that `claude update` ran with no session process alive and that every conversation was resumed by id. `qa:images-remote` (Windows) pairs a host and a viewer over real TLS and checks the same from the viewer: thumbnails and the full view cross the link, an attached JPEG lands on the host as PNG with the host path typed, and a non-image named `.png` or an unindexed id is refused over the link. `qa:restore-pacing` (Windows) checks that restored agents start one at a time: a fixture that draws for 2s while booting must not see the next one launched before it finished (measured before the fix: 26–49ms apart). None of these starts a real agent.
`qa:images` (Windows) drives the cockpit image strip, full-size viewer and 📎 attach against an isolated home holding a transcript with a tool screenshot, a pasted image and a written image file; its fixture `claude` echoes what it is sent, so an attached path is read back off the terminal. `qa:update` (Windows) checks "Update all": a fixture `claude` prints Claude Code's failed-update footer, and the harness asserts that `claude update` ran with no session process alive and that every conversation was resumed by id. `qa:images-remote` (Windows) pairs a host and a viewer over real TLS and checks the same from the viewer: thumbnails and the full view cross the link, an attached JPEG lands on the host as PNG with the host path typed, and a non-image named `.png` or an unindexed id is refused over the link. `qa:restore-pacing` (Windows) checks that restored agents start one at a time: a fixture that draws for 2s while booting must not see the next one launched before it finished (measured before the fix: 26–49ms apart). `qa:image-rows` (Windows) ties images to the terminal: a fixture `claude` draws a screen the way Claude Code does (`● server - tool (MCP)` calls, `⎿ [Image]` results, shaded `❯` prompts, a composer between rules) over a transcript holding the same screenshots, and the harness checks that each placeholder is marked and opens its own image, that the viewer shows what led to an image and scrolls the terminal to its row, that copying puts an image on the clipboard (the person's clipboard is restored afterwards), that a new screenshot is previewed while the strip is closed, and that Ctrl+Up/Down steps between sent prompts without entering the composer. None of these starts a real agent.

Do not run these against a live development conversation. Do not equate a short loopback test with sleep/resume, VPN changes or multi-day field validation.

Expand Down
20 changes: 20 additions & 0 deletions docs/releases/1.40.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# DevDeck 1.40.0

## Which step was this screenshot?

- **Image rows in the terminal.** Where Claude Code printed `[Image]` (a tool's screenshot) or `[Image #N]` (an image you pasted), the placeholder is now highlighted. Hover it for a thumbnail, click it for the full view. Each placeholder is checked against the tool named on the call line above it, so a row is never given another step's image. If the screen and the record don't line up, for example where Claude Code folded the output away, the row is simply left unmarked.
- **Show where it appeared.** The full-size viewer has a button that closes it and scrolls the terminal to the row the image was shown on, with the call that made it just above and the row briefly highlighted. The button is greyed out once that row has left the scrollback.
- **What led to it.** Thumbnails and the viewer now say what the tool was pointed at (an element, a file, a URL), the page the browser was on for a browser screenshot, and the last thing Claude said before taking it. A pasted image shows the words you sent with it. All of this comes from the session's own record, so it is there even when the terminal row is long gone.

## Smaller things

- **New screenshot preview.** While the image strip is closed, a new screenshot appears briefly in the corner of the terminal. Several in a row show as one preview with a count. Click it to open the image. It stays while the pointer is on it. Images you pasted yourself are not announced.
- **Copy image.** The viewer can put the image on the clipboard, ready to paste into another app or another session.
- **Ctrl+↑ / Ctrl+↓ between your prompts.** In a Claude session, jump to the previous or next prompt you sent. The landing row is briefly highlighted. Going past the last prompt returns to the bottom. Claude Code's own input box is never a stop, and the keys are never sent to the agent.

## Under the hood

- A new automated check (`qa:image-rows`) drives a fixture screen drawn the way Claude Code draws it. It covers marking and opening image rows, the viewer's context and "show in terminal", copying, the arrival preview and prompt jumps. It runs on every change on Windows.
- The terminal now enables xterm's marker and decoration API. Image rows are re-paired at most every 2.5 seconds, and only for the selected session when it has images; the performance gate is unchanged (no idle animation or DOM churn, no main-process stall while streaming).

The context lines need 1.40.0 on the PC running the session. With an older host the strip and viewer keep working without them.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "devdeck",
"version": "1.39.0",
"version": "1.40.0",
"description": "Project command deck — at-a-glance state + Claude Code, Codex, and Antigravity resume",
"main": "dist/main/main.js",
"type": "commonjs",
Expand Down Expand Up @@ -42,6 +42,7 @@
"check:docs": "node scripts/check-docs.mjs",
"qa:session-sync": "npm run build && node qa/session-sync.mjs",
"qa:images": "npm run build && node qa/images.mjs",
"qa:image-rows": "npm run build && node qa/image-rows.mjs",
"qa:images-remote": "npm run build && node qa/images-remote.mjs",
"qa:update": "npm run build && node qa/claude-update.mjs",
"qa:restore-pacing": "npm run build && node qa/restore-pacing.mjs"
Expand Down
Loading
Loading