diff --git a/CLAUDE.md b/CLAUDE.md index 050dac9..9841663 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -78,7 +78,7 @@ Data flow: `keypress → xterm onData → WS → pty.write() → shell stdin`, a - `attach(null)` → spawn a new PTY + shell; PTY output goes into a ~2MB **ring buffer** and (if a WS is attached) forwards live. - `attach(sessionId)` → look up the session, **replay the ring buffer**, then resume the live stream. This is what makes "refresh the page and the Claude session is still there" work. - WS close → `detach` one client (PTY keeps running), not kill; the idle clock starts only when the **last** client leaves. -- **Multi-device sharing (v0.4):** a session may have **many concurrent WS clients** — a new attach **JOINS (mirror)**, it does **not** kick. Output/exit/status broadcast to all; any client can type (shared control); the PTY size is the **min cols/rows across clients** (tmux-style). This relaxes the original "one WS per session" invariant (#5). `GET /live-sessions` lists running sessions so any device **auto-shows them as tabs**; `?join=` and the 🔗 share-QR open a specific shared session. +- **Multi-device sharing (v0.4):** a session may have **many concurrent WS clients** — a new attach **JOINS (mirror)**, it does **not** kick. Output/exit/status broadcast to all; any client can type (shared control). The PTY size is the **min cols/rows across *actively-viewing* clients** (tmux-style): a client only votes on size once it sends a `resize`, and a tab going hidden sends a `blur` to **withdraw its vote** (it still mirrors output). This stops a backgrounded mirror from clamping the shared PTY — and relaxes the original "one WS per session" invariant (#5). `GET /live-sessions` lists running sessions so any device **auto-shows them as tabs**; `?join=` and the 🔗 share-QR open a specific shared session; the **🗂 manage page** (`/manage.html`, `DELETE /live-sessions[/:id]`) lists/opens/kills sessions. - Orphan reclaim: detached longer than `IDLE_TTL` (default 24h) **with no new output since detach** → reclaim. (node-pty can't reliably detect a foreground child, so liveness is approximated via last-output time — see ARCHITECTURE §3.5 / M3.) On server exit, `pty.kill()` all sessions (no cross-restart persistence in v0.1; tmux backend is a v0.2 idea). Represent session state as immutable snapshots (id/start-time fixed at creation); hold mutable runtime handles (pty/ws) separately. diff --git a/docs/PROGRESS_LOG.md b/docs/PROGRESS_LOG.md index 045acc9..0f84df0 100644 --- a/docs/PROGRESS_LOG.md +++ b/docs/PROGRESS_LOG.md @@ -27,9 +27,11 @@ - **当前阶段**: **v0.3 全部完成**(H1–H4 + M3/M6/M7 已并入 main;**O2 历史浏览** 在分支 `o2-history`,待合并)。 - ✅ Step1 前端快赢 · ✅ H2/H4 状态感知 · ✅ H3 远程批准 · ✅ H1 tmux 保活 · ✅ M3/M7/M6 · ✅ **O2 历史会话浏览/resume** · ✅ tech-debt 清理(@ts-ignore 去掉)· ✅ UI:终端不再打印 Connecting/Connected(靠标签点)。 - ✅ **现代化 UI 主题**(design-token 调色板/靛蓝强调色/圆角芯片标签+键栏/毛玻璃弹层)· ✅ **键栏功能字幕**(每键下方标作用)+ 新增 ^R/^L/^D(共 17 键)· ✅ **⌨ 快捷键速查弹层**(`public/shortcuts.ts`)。 - - ✅ **v0.4 多设备共享会话**:放宽不变式 #5 —— 一个 session 可挂多个 WS 客户端(镜像;输出/退出/状态广播,谁都能打字,PTY 取各端最小尺寸 tmux 式)。`GET /live-sessions` + 打开应用自动把主机活动会话**显示为 tab**;`🔗` 分享二维码 / `?join=` 加入指定会话。浏览器实测:新设备自动发现并回放、两个并发客户端同收实时输出(clientCount=2)。 + - ✅ **v0.4 多设备共享会话**:放宽不变式 #5 —— 一个 session 可挂多个 WS 客户端(镜像;输出/退出/状态广播,谁都能打字)。`GET /live-sessions` + 打开应用自动把主机活动会话**显示为 tab**;`🔗` 分享二维码 / `?join=` 加入指定会话。 + - ✅ **镜像尺寸 bug 修复**:PTY 尺寸只取**正在查看**的客户端的最小值 —— attach 不再预置默认尺寸投票;标签隐藏发 `blur` 撤回投票(仍镜像输出),`show()` 重新投票。修复了"后台镜像把共享 PTY 卡在 80×24"导致镜像看起来坏掉的问题(单测覆盖)。后端纯客户端实测:两端镜像输出 + 共享输入均通过。 + - ✅ **🗂 会话管理页**(`/manage.html` 独立页):列出主机所有运行中 session(id/目录/状态/观看数/尺寸/时长),可 Open/Kill,批量 Kill all / Kill detached;`DELETE /live-sessions[/:id]`。实测 3→2→0。 - ⬜ 仅剩:**O1 token 认证**(可选,默认关)+ **F4/F7 真机验收**(局域网/手机)。 - - **222 测试全绿**;工具栏 🔍搜索 ⚙设置 ▦仪表盘 🕘历史 ⌨快捷键 🔗分享 📱QR。 + - **225 测试全绿**;工具栏 🔍搜索 ⚙设置 ▦仪表盘 🕘历史 ⌨快捷键 🔗分享 🗂管理 📱QR。 - **下一步**: O1(可选)或真机验收。 - v0.2/v0.1 历史见下方条目。 - **Wave**: **W0–W5 基本完成**。v0.1 功能完整、测试与真机浏览器验证通过。仅剩 2 项需用户真设备。