Skip to content

(session-state): local-pty rows carry a persistent state like the other adapters - #282

Merged
devsuitup merged 2 commits into
mainfrom
feat/246-local-pty-state
Sep 13, 2026
Merged

devsuitup merged 2 commits into
mainfrom
feat/246-local-pty-state

Conversation

@devsuitup

@devsuitup devsuitup commented Sep 13, 2026

Copy link
Copy Markdown
Owner

Finishes #246 (steps 1-5 shipped in #266#270; #273 added the ownership rule). This closes the last gap: the local-pty kind now holds a persistent createSessionState per session like remote-ssh and local-transcript, instead of projecting from the legacy Maps at render time.

What

  • public/session-activity.js is the local-pty adapter: localPtyStates (one state per id) fed by setActivity, clearUnread, new setAttention(sessionId, on, via), syncLocalPtyAgentsBusy (aggregate of activeSubagentsByParent), rekeyActivityState, purgeActivityFor. Exported signatures unchanged. sessionBusyState / responseReadySessions / attentionSessions remain as Map/Set-shaped views over the states for the two readers not migrated (sidebar initial paint, grid-card dot) and for tests.
  • public/session-activity-dom.js: applyStateClasses(sessionId, snapshot) is the single projection for all three kinds and now writes needs-attention too; computeBusyReadyClasses / applyActivityClassesToElement removed; snapshotForLocal is a thin wrapper.
  • app.js: notifications go through setAttention; sidebar.js: subagent running state mirrored into the adapter.
  • Exclusivity of busy / response-ready / attention now lives only in session-state.js apply().
  • Decided semantic, documented and pinned: an attention event consumes the unseen-response state — clearing attention lands on idle, not on response-ready (before: independent Sets, CSS precedence, fallback to response-ready).
  • Docs: session-state.md (status complete, local-pty section, ports table corrected), ipc-bridge.md.

Proof

  • DOM output unchanged except the two decided semantics (attention orthogonal to busy; local idle-while-active reads "Waiting for input") — see the review comment; the full pinning suite is green (dom-sidebar-icon-slot, sidebar-busy-agents-tint, session-icon-slot-css-boundary, dom-sidebar-subagent-running, remote-row-ownership, remote-session-adapter, local-transcript-adapter, activity-trace-renderer, running-indicators, dom-file-panel-changes).
  • test/local-pty-adapter.test.js (12): sequence → snapshot, combined states impossible through the API, rekey/purge move/drop the object, the decided attention semantic, a mutation guard.
  • Mutation: setActivity writing sessionBusyState.set() directly instead of apply() → 3 tests red; reverted.
  • Three tests in session-activity.test.js that forced now-impossible combinations were rewritten to cover the same regressions without them.
  • task check: 1431 + 120 pass, 0 fail, pre-existing skips.

Left as is: activeSubagentsByParent (per-agent TTL tracking) is a different concern; its aggregate is mirrored, not replaced.

…er adapters

Finishes the #246 migration. public/session-activity.js is the local-pty
adapter: one createSessionState per session id, fed by setActivity,
clearUnread, setAttention, subagent counts, rekey and purge; the legacy Maps
are views over those states, and busy / response-ready / attention
exclusivity lives only in the domain. One snapshot-driven projection paints
every kind, needs-attention included. Decided and pinned: attention
supersedes and consumes the unseen-response state.
…entry on remote detach

Review follow-up on the local-pty migration. Attention is cleared only by an
explicit clear, never by a busy title; the projection reads busy, attention
and response-ready off the snapshot rather than the winning rung so both can
show together; a local row idling while active reads "Waiting for input"
(decided, pinned); syncLocalPtyAgentsBusy no longer creates states and the
remote detach handoff purges the shadow local-pty entry.
@devsuitup

Copy link
Copy Markdown
Owner Author

Adversarial review (main vs branch in jsdom) → second commit. "DOM output unchanged" in the body reads: unchanged except two decided semantics.

  1. MAJOR — an OSC-0 busy title while a permission prompt is open wiped needs-attention. Fixed in the domain: clearExclusive() no longer touches attention; a busy edge leaves it, only an explicit clear removes it. The projection now reads busy / attention / response-ready off the snapshot rather than the winning rung, so both classes show together as on main. Tests: attention → busy → both classes; clear attention → busy remains. Mutation: restoring attention = false in clearExclusive() → 3 tests red.
  2. MAJOR — a local row idling while active (or via an armReady:false source) now reads "Waiting for input" instead of "Idle". Kept as a convergence with remote and local-transcript rows; documented under "Decided" and pinned by two tests (active → session-icon--waiting; not active → response-ready, unchanged).
  3. MINOR — docs/activity-trace.md: needs-attention is a field of class.apply now; class.toggle only carries has-running-pty. One assertion added.
  4. MINOR — syncLocalPtyAgentsBusy no longer creates a state; setRemoteAttached(id,false) purges the shadow local-pty entry (remote-detach). Two tests.

task check: 1440 + 120 pass, 0 fail.

@devsuitup
devsuitup merged commit da29777 into main Sep 13, 2026
10 checks passed
@devsuitup
devsuitup deleted the feat/246-local-pty-state branch September 13, 2026 01:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant