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: 2 additions & 2 deletions 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.37.9** adds confirmed session renames and task conflict protection ([release notes](docs/releases/1.37.9.md)). Use 1.37.9 on both machines for the new write protocol. See [the maintenance review](docs/quality-review-2026-09-08.md) and [session synchronization review](docs/session-sync-review-2026-09-08.md).
> **1.38.0** makes closing a session reliable across paired PCs, fixes stale terminal drawing, adds **Apply update** for Claude Code on Windows, protects notes from being overwritten by another device, and cuts background CPU use ([release notes](docs/releases/1.38.0.md)). Use 1.38.0 on both machines for confirmed remote close and versioned notes; 1.37.9 added confirmed session renames and task conflict protection ([notes](docs/releases/1.37.9.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 Expand Up @@ -83,7 +83,7 @@ Both machines must be reachable, for example on the same LAN, through an existin
| Application settings | Belong to the PC whose Settings screen you are using. |
| Terminal screen | The host provides bounded recent output for reconstruction, not an unlimited durable archive. |

**Compatibility:** confirmed titles and task editing need compatible 1.37.9-or-newer builds on both ends. The app checks title-version support and refuses unversioned writes rather than silently treating a viewer-only rename as shared success. Titles of disconnected or ended sessions cannot be remotely committed.
**Compatibility:** confirmed titles and task editing need compatible 1.37.9-or-newer builds on both ends; confirmed remote close and versioned notes need 1.38.0 on both ends (with an older peer they fall back to the previous behavior). The app checks title-version support and refuses unversioned writes rather than silently treating a viewer-only rename as shared success. Titles of disconnected or ended sessions cannot be remotely committed.

Reconnecting reads the host's current title; it must not send an old cached title back. Clearing a custom title is an explicit change to the default project name, not an invitation to restore the old name. See [state ownership and consistency](docs/state-consistency.md) for the implementation contract and remaining gaps.

Expand Down
5 changes: 4 additions & 1 deletion docs/backlog.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@ Updated 2026-09-08. The 1.37.9 maintenance work was released on 2026-10-15. Impl
| P2 | Persistent terminal history | Separate screen reconstruction from archive; bounded retention, deletion/export, redaction and visible gaps |
| P2 | Task operation API | Task-ID mutations after revision-checked baseline; explicit same-task conflicts and concurrent create/edit/delete/clear-completed checks |
| P1 | Remaining shared-metadata migrations | Apply the [ownership contract](state-consistency.md) to notes, project flags and Link settings; explicit failure/conflict UI and multi-observer QA |
| P2 | Note concurrency | Notes remain last-write-wins across devices; add revision checks while preserving drafts |
| P2 | Focused module extraction | Terminal lifecycle/rendering boundaries protected by regression tests; no rewrite solely for file length |

## Implemented in 1.38.0

Reliable session close across paired PCs (answered remote close, offline closes delivered on reconnect, tombstones against re-adoption, `closed` exits), DOM terminal rendering, Apply update for Claude Code, versioned notes, Windows process-tree kill, Link pre-auth/notify/event hardening, scan performance and spinner CPU reduction, and the supervised `qa:close` harness. See the [release notes](releases/1.38.0.md).

## Implemented in 1.37.9

Revision-checked task writes, legacy refusal, conflict review with retained attempted change, settings save rollback and inline validation, js-yaml/Vitest advisory fixes, Node24 CI, maintenance regression gates, fail-closed performance preconditions, and current documentation/maintenance configuration. See the candidate review for evidence and limits.
Expand Down
2 changes: 1 addition & 1 deletion docs/quality.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Results and screenshots are written to `qa/shots/maintenance/` and `qa/shots/res

## Manual harnesses

`qa:link` is a supervised two-app harness that may start installed provider CLIs. `npm run qa:perf -- 4 --allow-live-agents` is a manual Windows benchmark and explicitly opts into real-agent startup. Performance QA refuses missing terminals, invisible workload, incomplete streaming/repaint activity and missing CPU samples instead of treating low CPU as success. It has not become a deterministic CI performance gate; that conversion remains a separate task.
`qa:link` is a supervised two-app harness that may start installed provider CLIs. `qa:close` is a supervised two-app harness for the session close lifecycle (remote, offline, refused and bulk close, adoption focus, restart, Apply update); it starts the installed `claude` CLI in a throwaway repository and sends no prompts. `npm run qa:perf -- 4 --allow-live-agents` is a manual Windows benchmark and explicitly opts into real-agent startup. Performance QA refuses missing terminals, invisible workload, incomplete streaming/repaint activity and missing CPU samples instead of treating low CPU as success. It has not become a deterministic CI performance gate; that conversion remains a separate task.

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
36 changes: 36 additions & 0 deletions docs/releases/1.38.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# DevDeck 1.38.0

## Closing sessions

- A session closed on one PC disappears from every paired PC. It no longer stays behind as an "exited" tile that was saved and reopened as a previous session — or started again by an update restart.
- Closing several sessions at once no longer brings some of them back as dead tiles.
- Closing a session on another PC now waits for that PC's answer. If the PC is offline, the close is delivered when it reconnects (also after restarting DevDeck). If this device may not control that PC's sessions, the tile comes back with an explanation instead of looking closed while the agent keeps running.
- Closing a session on Windows also ends what the agent started in the background (MCP servers, hidden dev servers).
- A renderer crash no longer stops every running agent; the window reloads and picks the sessions back up.

## Terminals

- Terminals draw with the DOM renderer. Under the WebGL renderer, Claude Code's screen could keep stale cells — old status lines stacked down the screen and earlier text showing through gaps — until the window was minimized and restored.
- When Claude Code shows "Update installed · Restart to apply", the session header offers **Apply update**. It restarts the session on the new version and keeps the conversation; during a running turn it waits for the turn to finish. (Claude Code's own `/restart` is not available on Windows.)
- A session started from another PC no longer takes the screen or keyboard focus.
- "+ New session" on a remote session opens on that PC. Opening from the task board or the project memory window opens on the machine those projects belong to.
- Resizing the window no longer marks every idle session as working.

## Data safety

- Notes are saved with a revision. If another device saved the note first, both versions are shown so nothing is overwritten unseen. Older paired builds keep working without the check.
- Usage totals could double when two scans read the same growing transcript at once; they no longer do.
- The project card shows the real number of sessions instead of stopping at 5.

## Performance

- Working-session spinners cost roughly a quarter of the CPU they did (measured 16.0% → 3.6% of one core with 12 sessions, 6 working) and stop while DevDeck is not focused.
- Codex session lookups and usage scans no longer stall the app (100 projects: 18.8 s → 0.3 s; longest stall 84–99 ms → 6–11 ms).

## Security and robustness

- Paired machines: stricter checks for unauthenticated connections, request types and rate limits, event forgery, audit-log flooding, removed machines reconnecting, and remote writes to paths that are not real projects.
- Opening a folder in VS Code no longer expands `%VAR%` in its name; `;` in folder names no longer breaks Windows Terminal tabs.
- Electron 43.7, no open dependency advisories.

Remote close confirmation and versioned notes need 1.38.0 on both PCs to take effect; with an older peer DevDeck falls back to the previous behavior.
4 changes: 3 additions & 1 deletion docs/state-consistency.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ Related paths treated cached session labels as authority when attaching, used ba
| Session title | Main process of the machine running the terminal | Permission + terminal incarnation + expected label revision; persist before publishing/acknowledging | All renderers, including the host, consume the owner snapshot. Drafts are separate. |
| Saved session membership and pins | Each viewer | Local persistence; overlay host-owned titles when reconciling local live sessions | Never send cached titles back merely because a viewer attached or restarted. |
| Project task list | Main process owning the project | Expected task revision; reject conflicts; no silent retry | Display returned snapshot; preserve unsaved attempted change. |
| Project notes/flags | Project-owning machine | Existing last-write-wins behavior | Not yet covered by title/task CAS guarantees. |
| Project notes | Project-owning machine | Expected note revision (`project:saveNote`, 1.38.0); legacy `setNote` still accepted and bumps the revision | On conflict show both the saved note and the attempted one; nothing is overwritten unseen. |
| Project flags (pin/hide) | Project-owning machine | Last-write-wins; remote writes only to scanned projects | Not yet covered by CAS guarantees. |
| Session membership (close) | Machine running the terminal | `cockpit:closeSession` answers ok/offline/denied; closes owed to an offline machine are kept (also across restarts) and delivered on reconnect | Closed ids are tombstoned until the machine stops listing them; an exit carries `closed`/`closedBy` so every deck removes the tile. |
| Settings | Current PC | Await write; rollback or retain invalid draft with explicit feedback | No success state before persistence. Link settings still need broader failure coverage. |
| Terminal input/output | Host terminal | Ordered byte stream; do not turn every keystroke into a storage transaction | Screen replay is bounded and is not an archival transcript. |

Expand Down
118 changes: 22 additions & 96 deletions package-lock.json

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

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "devdeck",
"version": "1.37.9",
"version": "1.38.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 @@ -34,6 +34,7 @@
"qa": "npm run build && node qa/screenshot.mjs",
"qa:audit": "npm run build && node qa/audit.mjs",
"qa:link": "npm run build && node qa/link.mjs",
"qa:close": "npm run build && node qa/close.mjs",
"qa:resilience": "npm run build && node qa/resilience.mjs",
"qa:perf": "npm run build && node qa/perf.mjs",
"qa:maintenance": "npm run build && node qa/maintenance.mjs",
Expand Down Expand Up @@ -119,11 +120,11 @@
"@fontsource-variable/geist": "5.3.0",
"@homebridge/node-pty-prebuilt-multiarch": "^0.13.1",
"@xterm/addon-search": "^0.16.0",
"@xterm/addon-webgl": "^0.19.0",
"electron-updater": "^6.8.9"
},
"overrides": {
"undici": "^6.28.0",
"form-data": "^4.0.6"
"form-data": "^4.0.6",
"global-agent": "^4.1.3"
}
}
Loading
Loading