Merge master into PR #157 (session manager polish)

Resolutions (sse-events.ts / constants.js / app.js): unions of the docker/
multi-user event registrations from master with the session-order/pin events
from this branch.

Additions on top of the merge:
- POST /api/sessions/:id/pin now falls back to the persisted store record when
  no live session exists: COD-142 deliberately preserves pinned records after
  kill (and cleanupStaleSessions skips them), so without this a pinned-then-
  killed session could never be unpinned. Owner-scoped in multi-user mode.
- SessionOrderUpdateSchema bounds (id <= 100 chars, <= 500 entries) so a buggy
  client can't persist megabytes into state.json; empty strings still flow to
  normalizeSessionOrder which drops them.
- Route tests for the persisted-record pin fallback.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer
2026-07-20 14:31:44 +02:00
98 changed files with 13899 additions and 650 deletions
+86
View File
@@ -3952,6 +3952,37 @@ body.touch-device .terminal-container .xterm .xterm-helper-textarea {
transition: background var(--transition-smooth);
}
/* COD-105 — discovered remote tmux sessions list (remote-case flow). */
.remote-discover-results {
display: flex;
flex-direction: column;
gap: 6px;
margin-top: 8px;
}
.remote-discover-item {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
padding: 8px 10px;
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(255, 255, 255, 0.06);
border-radius: 6px;
}
.remote-discover-info {
display: flex;
flex-direction: column;
gap: 2px;
min-width: 0;
}
.remote-discover-name {
font-weight: 600;
font-size: 0.85rem;
}
.case-manage-item:hover {
background: rgba(255, 255, 255, 0.06);
}
@@ -5402,6 +5433,7 @@ body.touch-device .terminal-container .xterm .xterm-helper-textarea {
/* Modal Tabs */
.modal-tabs {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
padding: 0 1rem 0.75rem 1rem;
border-bottom: 1px solid var(--border);
@@ -9466,6 +9498,24 @@ kbd {
padding-left: 0.5rem;
}
/* "Run in Docker" quick option — the primary one-click entry point, so its
label + hint read larger and brighter than the standard form label/hint. */
.docker-quick-row .checkbox-row {
font-size: 0.9rem;
color: var(--text);
}
.docker-quick-row .form-hint {
font-size: 0.8rem;
line-height: 1.45;
}
/* The container-settings panel is always shown + expanded (no longer gated on
the checkbox), so its summary header reads a touch larger too. */
.docker-quick-settings > summary {
font-size: 0.85rem;
}
/* ═══════════════════════════════════════════════════════════════
Response Viewer — native-scroll overlay for reading Claude responses
═══════════════════════════════════════════════════════════════ */
@@ -9490,6 +9540,42 @@ kbd {
display: none !important;
}
/* "Session Manager" + "Away Digest" header buttons — opt-in (App Settings →
Display), hidden by default. Same marker pattern as the response viewer: a
base inline-flex !important so an inline style can't override it, and a
more-specific marker rule to hide. Phones keep them hidden regardless via the
higher-specificity mobile.css rule (.btn-icon-header.btn-...). */
.btn-session-manager {
display: inline-flex !important;
}
.btn-session-manager.btn-session-manager--hidden {
display: none !important;
}
.btn-away-digest {
display: inline-flex !important;
}
.btn-away-digest.btn-away-digest--hidden {
display: none !important;
}
/* "File Viewer" header button — opt-in (App Settings → Header Displays), hidden
by default. Clicking it toggles the file browser panel. Same marker pattern as
the response viewer: a base inline-flex !important so an inline style can't
override it, and a more-specific marker rule to hide. */
.btn-file-viewer {
display: inline-flex !important;
}
.btn-file-viewer.btn-file-viewer--hidden {
display: none !important;
}
/* "Cron" footer-toolbar button — shown by default (App Settings → Display can
hide it). Toolbar button, not a header icon, so only the hide marker is
needed; out-specify any base .btn-toolbar display. */
.btn-toolbar.btn-cron--hidden {
display: none !important;
}
/* "Ultracode Agents" header launcher — opt-in (App Settings → Display), hidden by
default everywhere (so the mobile-header-buttons-policy guard auto-excludes it).
Base inline-flex !important + a more-specific marker rule to hide. */