COD-139 add session pinning (float pinned sessions to top of session manager list)

Pin/unpin a session via POST /api/sessions/:id/pin {pinned}; pinned sessions
sort above unpinned in the unified session manager list (COD-121), ordered by
pinnedAt descending. Pin state lives on SessionState, persists to state.json,
and survives reload/reconnect/restart (persisted-input carries pinned; the
merge skips undefined so a recovered live session can't clobber it). New SSE
event session:pinned re-sorts the open list live across clients. Pin/Unpin
affordance in the session-row kebab menu with a 📌 glyph + amber highlight.

(cherry picked from commit 82749747039afcd4a3104f6a97ce7d3c2ddd048d)
This commit is contained in:
Aamer Akhter
2026-07-17 16:25:29 -04:00
parent 8807b3ff6d
commit 5792c2d62e
13 changed files with 413 additions and 3 deletions
+20
View File
@@ -1436,6 +1436,26 @@ class CodemanApp {
for (const event of [SSE_EVENTS.SESSION_CREATED, SSE_EVENTS.SESSION_DELETED]) {
addListener(event, () => this._onSessionListMaybeChanged());
}
// COD-139: a session:pinned event updates the local live-session pin flag (so
// a subsequent render is consistent) and re-sorts the open session manager /
// welcome list so pinned sessions float to the top.
addListener(SSE_EVENTS.SESSION_PINNED, (e) => {
let data = null;
try {
data = JSON.parse(e.data);
} catch {
/* ignore malformed payload */
}
if (data && data.id) {
const live = this.sessions.get(data.id);
if (live) {
live.pinned = data.pinned === true;
live.pinnedAt = data.pinned ? data.pinnedAt : undefined;
}
}
this._onSessionListMaybeChanged();
});
}
// ═══════════════════════════════════════════════════════════════