Skip to content

feat: realtime HTML update via WebSocket#61

Merged
Svtter merged 2 commits into
mainfrom
worktree-realtime-html-update
May 21, 2026
Merged

feat: realtime HTML update via WebSocket#61
Svtter merged 2 commits into
mainfrom
worktree-realtime-html-update

Conversation

@Svtter
Copy link
Copy Markdown
Contributor

@Svtter Svtter commented May 21, 2026

Summary

  • Add live reload support for preview sessions via WebSocket
  • When files are updated via the incremental upload API, connected browsers automatically refresh
  • Add sth watch command for local directory monitoring and auto-sync to remote sessions

Key Components

  • WebSocket Hub/Client: Per-session connection management with broadcast
  • HTML Injection Middleware: Adds live reload script to served HTML pages
  • Incremental File Update API: PUT /api/sessions/:id/files for partial updates
  • File System Watcher: Server-side watcher with 300ms debounce
  • sth watch CLI: Monitors local directory and auto-uploads changes

Test plan

  • Unit tests for inject middleware (skip non-session, add script, skip non-HTML, skip WS path)
  • Unit tests for Hub broadcast and onEmpty callback
  • Unit tests for WebSocket handler
  • E2E test: WS client connects, receives reload after file update
  • go vet ./... clean
  • All existing tests pass

Closes #60

🤖 Generated with Claude Code

Add live reload support for preview sessions. When files are updated
via the incremental upload API, connected browsers automatically refresh.

- WebSocket hub/client architecture for per-session connection management
- HTML injection middleware that adds live reload script to served pages
- PUT /api/sessions/:id/files API for incremental file updates
- sth watch command for local directory monitoring and auto-sync
- File system watcher with 300ms debounce for server-side changes

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

No gaps found. Let me verify by cross-referencing the spec items one more time:

Spec (Issue #60) requirements vs implementation:

Spec Item Implementation Status
Real-time HTML auto-refresh when backend updates files WebSocket hub + broadcast on file update
Enter a session → get live reload Inject middleware adds WS script to /s/{id}/ HTML pages
WebSocket connection HandleWebSocket in handler.go upgrades HTTP to WS, registers in hub
Backend file update triggers refresh handleUpdateFiles broadcasts ReloadJSON() via liveMgr.BroadcastTo
Server-side file watcher WatchDir in watcher.go with 300ms debounce, integrated via Manager
sth watch CLI internal/cli/watch.go with fsnotify monitoring + upload to API

All functional requirements from the spec are fully implemented and integrated. The only notable observation is that Hub.onChange (internal/live/hub.go:28, line 108) is set but never invoked by any Hub method — however, the actual change notification/broadcast works correctly through two separate paths (the notify callback passed to WatchDir in GetOrCreateHub, and BroadcastTo called directly from handleUpdateFiles in server.go). This dead field does not constitute a missing feature since all spec behaviors are covered.

无遗漏

New%20session%20-%202026-05-21T10%3A00%3A25.023Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

可合并

总结:该 PR 通过 WebSocket 实现了实时 HTML 刷新功能,新增 sth watch CLI 命令、HTML 注入中间件、WebSocket Hub/Client 管理及文件增量更新 API。代码结构清晰,go vetgo build 及所有现有测试均通过。

阻塞项:无

建议项:

  1. internal/live/handler.go:50-64extractSessionID 硬编码 /s/ 前缀长度 3,若路由变更容易静默失效,建议用 strings.TrimPrefix 替代
  2. internal/live/inject.go:91-96realHeader 方法逻辑令人困惑(内部状态不同时行为不同),建议简化为仅在需要时调用 w.WriteHeader
  3. internal/server/server.go:1626for key, headers := rangekey 未使用(_ = key 多余),可删除
  4. internal/server/server.go:1629hdr.Size > maxIncrementalBytes 检查是冗余的,MaxBytesReaderParseMultipartForm 已限制请求体大小
  5. internal/live/hub.go:135-143BroadcastTo 在释放 m.mu 后调用 entry.hub.Broadcast,存在 TOCTOU 竞态(hub 可能被并发删除),虽然安全但建议加注释说明
  6. internal/live/watcher.go — Server 端 WatchDir 不忽略隐藏文件/临时文件(如 .swp),而 CLI 端 shouldIgnorePath 会忽略,行为不一致
  7. 缺少对 handleUpdateFiles 的单元测试(仅依赖 E2E 测试覆盖)
  8. internal/cli/watch.go:183-244uploadFiles 中出错时(如文件不存在)直接 continue 但不记录日志,用户可能无感知

New%20session%20-%202026-05-21T10%3A00%3A25.239Z
opencode session  |  github run

- Use strings.TrimPrefix instead of hardcoded index in extractSessionID
- Remove unused _ = key in handleUpdateFiles
- Add TOCTOU safety comment in BroadcastTo
- Add hidden/temp file filtering to server-side WatchDir
- Log errors when uploadFiles cannot open a file

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

无遗漏

所有 spec(Issue #60)需求均已完整实现:

Spec 需求 实现位置 状态
进入 session 后前端自动刷新 internal/live/inject.go:14-31 — JS 脚本注入 HTML,自动建立 WS 连接
WebSocket 连接管理 internal/live/handler.go:12-48 — WS 升级 + 注册客户端;hub.go:40-57 — Register/Unregister
后端更新 HTML 文件时推送通知 internal/server/server.go:1684BroadcastTo 在 API 更新后调用;hub.go:122-125 — 文件监控回调
WebSocket Hub 广播 hub.go:60-71Broadcast 遍历客户端发送
增量文件更新 API server.go:1597-1690PUT /api/sessions/:id/files
文件系统监听器 internal/live/watcher.go:15-65 — 递归监听 + 300ms 防抖
sth watch CLI internal/cli/watch.go:23-65 — 本地目录监听 + 自动上传
中间件集成 server.go:447InjectMiddleware 包裹路由
WS 路由注册 server.go:562-578 — 在 routes() 中注册 /s/{id}/ws

所有功能点均完整实现并正确集成,无遗漏。

New%20session%20-%202026-05-21T10%3A08%3A31.236Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

可合并

New%20session%20-%202026-05-21T10%3A08%3A30.394Z
opencode session  |  github run

@Svtter Svtter merged commit 8b0658e into main May 21, 2026
4 checks passed
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.

支持 realtime update HTML(后端更新后前端自动刷新)

1 participant