Skip to content

Per-terminal privacy (toggle + wipe) + free-form sessions (create + real close)#34

Open
falkoro wants to merge 1 commit into
masterfrom
feat/privacy-sessions
Open

Per-terminal privacy (toggle + wipe) + free-form sessions (create + real close)#34
falkoro wants to merge 1 commit into
masterfrom
feat/privacy-sessions

Conversation

@falkoro
Copy link
Copy Markdown
Owner

@falkoro falkoro commented Jun 2, 2026

Builds the two approved features. Not merging yet — recommend deploying #33 (stabilization) first and confirming the live instance is happy, then merge + deploy this.

B2 — Per-terminal privacy

  • Private-mode toggle per shell (persisted in private-sessions.json): redacts that session's preview, work-title and SSE output server-side, and excludes it from the summary LLM.
  • A private session cannot be opened as a live terminal/api/term returns 403 and Shell-in is disabled — so its output never leaves the server. (This closed the one real leak the review found.)
  • One-tap wipe (/api/wipe): tmux clear-history + clear screen + evict cached summary + scrub local preview cache.

B3 — Free-form sessions

  • New session form: name + command + cwd (validated; cwd must exist), creates a real tmux session, persisted in dynamic-sessions.json (survives restart), merged into the session list.
  • Close on a dynamic session kills and removes it (config slots keep the existing kill-only Stop); removal also clears any stale private flag.

New modules src/dynamic_sessions.rs + src/private_sessions.rs. All new endpoints gated by require_unlock + CSRF action header.

Verification

3-lens adversarial review (security/correctness/frontend): gating correct on all 5 endpoints, command/cwd handling safe (argv not shell), 31 tests pass, no formatting churn. The HIGH finding (live-terminal privacy bypass) was fixed and I re-verified end-to-end: private → WS 403 + /api/shells output redacted; Shell-in disabled + "output hidden" placeholder + work-title blank; non-private opens normally; free-form create → real tmux session → close kills + removes. 0 console errors.

🤖 Generated with Claude Code

… real close)

B2 — privacy: a per-shell private-mode toggle (persisted in
private-sessions.json) redacts that session's preview, work-title, and
SSE output server-side and excludes it from the summary LLM. A private
session also cannot be opened as a live terminal — /api/term returns 403
and the Shell-in control is disabled — so a private session's output
never leaves the server. Plus a one-tap wipe (/api/wipe) that runs tmux
clear-history + clears the screen, evicts the cached summary, and scrubs
the local preview cache.

B3 — free-form sessions: a "New session" form creates a real tmux
session (name + command + cwd, validated; persisted in
dynamic-sessions.json so it survives restarts) and merges into the
session list; Close on a dynamic session kills it AND removes it (config
slots keep the existing kill-only Stop). Removing a session also clears
any stale private flag.

New modules src/dynamic_sessions.rs + src/private_sessions.rs (tolerant
JSON stores, strict name/cwd validation). All new endpoints gated by
require_unlock + the CSRF action header. Reviewed by a 3-lens adversarial
pass; the one real leak (live-terminal bypass of privacy) is fixed and
verified (WS 403, preview redacted, create/close round-trip).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 2, 2026 20:59
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements two new backend+frontend features for ShellDeck session management: per-session privacy (server-side redaction + terminal block + wipe) and persisted “free-form” (dynamic) tmux sessions that can be created and fully removed.

Changes:

  • Adds per-session privacy state persisted to private-sessions.json, redacting preview/title/summary context and blocking /api/term for private sessions.
  • Adds dynamic sessions persisted to dynamic-sessions.json, including create + true close/remove semantics.
  • Extends UI controls to toggle privacy, wipe a session, and create/close dynamic sessions, including updated styling.

Reviewed changes

Copilot reviewed 19 out of 20 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/tmux.rs Adds managed session abstraction, dynamic session create/remove, private redaction in shell previews, and wipe support.
src/term.rs Blocks WebSocket terminal access for private sessions.
src/summary.rs Excludes private sessions from summary LLM context.
src/routes.rs Adds /api/private, /api/wipe, and dynamic session create/remove endpoints with unlock + CSRF action gating.
src/private_sessions.rs New module for persisting/loading private session set.
src/dynamic_sessions.rs New module for persisting/loading/validating dynamic session definitions.
src/main.rs Registers new Rust modules.
src/config.rs Adds config paths for private/dynamic session state files.
public/terminal.js Prevents opening terminals for private sessions; exposes close-by-session helper.
public/render.js Adds privacy toggle + wipe UI, and private-mode rendering behavior.
public/events.js Wires click handlers for privacy/wipe/new session and dynamic close behavior.
public/core.js Tracks private sessions client-side; updates UI state and local caches accordingly.
public/actions.js Implements /api/private, /api/wipe, and /api/sessions/* client actions and new-session modal.
public/app.css Styles for private mode and new session modal layout.
frontend/terminal.ts TS source for terminal private-session gating + close helper.
frontend/render.ts TS source for privacy/wipe UI and private-mode rendering behavior.
frontend/events.ts TS source for wiring privacy/wipe/new session and dynamic close behavior.
frontend/core.ts TS source for private session state tracking + UI updates.
frontend/actions.ts TS source for private toggle, wipe, and dynamic session create modal/actions.
.gitignore Ignores runtime JSON state files for dynamic/private sessions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/routes.rs
Comment on lines +564 to +568
if body.private {
if let Ok(mut cache) = state.summary_cache.lock() {
*cache = None;
}
}
Comment thread src/tmux.rs
Comment on lines +297 to +298
let managed = managed_sessions(config.clone()).await;
let private = private_sessions::load(config.clone()).await;
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.

2 participants