Skip to content

feat: UI enhancements and multi-client TTY support#25

Merged
linletian merged 15 commits intodevelopfrom
feature/ui-update
Mar 23, 2026
Merged

feat: UI enhancements and multi-client TTY support#25
linletian merged 15 commits intodevelopfrom
feature/ui-update

Conversation

@linletian
Copy link
Copy Markdown
Owner

功能改进总结

本分支包含以下主要功能改进:

核心功能

  1. 多客户端 TTY 尺寸同步 - 服务器追踪所有连接的客户端,计算最小尺寸作为共享 PTY 尺寸,支持每实例最多 8 个客户端
  2. 资源监控器 - 新增 CPU%、内存 RSS 统计,按 worktree 分组显示,支持 1 秒轮询
  3. 终端控制增强 - 添加刷新、滚动到底部功能,使用 AbortController 取消进行中的请求

UI/UX 改进

  1. 浏览器关闭保护 - beforeunload 事件触发原生确认对话框,防止误操作关闭页面
  2. Git 变更面板 - 智能路径截断的 git changes 显示
  3. Worktree 快捷操作 - 快速打开 Terminal/Finder
  4. 实例重命名支持 - PATCH /api/instances 支持更新实例显示名称
  5. 标签页重排序 - 使用乐观锁实现拖拽重排序
  6. 实时分支追踪 - 带超时保护的 git 命令
  7. 主仓库实例支持 - 支持在主 git 仓库中运行实例
  8. 页面标题增强 - 添加仓库名到页面标题,带 XSS 保护
  9. 键盘快捷键 - 按 'o' 键打开浏览器

技术改进

  • 乐观锁防止并发冲突
  • 每实例终端会话保持
  • 归档实例清理功能

测试状态

  • 所有现有测试通过
  • 代码格式化符合 gofmt 标准

linletian and others added 14 commits March 20, 2026 23:09
- Pass repo name to ui.Register() and substitute <title> tag
- Use html.EscapeString() to prevent XSS attacks
- Add indexHTMLReader variable for testability
- Add comprehensive tests for error paths and special characters
- Update CLAUDE.md with terminal protocol documentation
- Update GitNexus index metadata

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
- Add GET /api/main endpoint to fetch main repo name and branch
- Add MainWorktreeID constant for main repo instances
- Add CurrentBranch() function with proper error handling
- Support Root parameter in instance.StartInput for non-worktree paths
- Update UI sidebar to show main workspace as pinned item
- Auto-select main repo when no worktrees exist

The main repo instance feature allows users to run commands in the
host git repository without creating a worktree, useful for quick
operations like git status or running mw commands.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
- List() now queries current branch for each worktree via git rev-parse
- GitCommand() helper in gitx package centralizes timeout-protected git execution
- currentBranch() returns (string, error) to distinguish errors from empty values
- On error (path gone, detached HEAD), List() keeps stored Branch value
- All git commands now have WaitDelay timeouts (2s/5s/10s based on operation)
- Docs updated: API.md, ARCHITECTURE.md, CLAUDE.md clarify 'branch' is live value
- Main Workspace support documented for running instances in main repo

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Backend:
- Add ErrInstanceNotFound variable for proper error handling
- Add UpdateName() method to instance.Manager, return updated instance
- Add PATCH /api/instances endpoint with {id, name} body
- Use errors.Is() for error classification

Frontend:
- Double-click instance tab to rename inline
- Skip refresh() render during rename to preserve IME composition
- Commit rename on Enter, cancel on Escape
- Protect focus from terminal during rename
- Simplify state management

Docs:
- Update API.md with Rename endpoint spec
- Update ARCHITECTURE.md and CLAUDE.md

Tests:
- Add TestHandleInstanceUpdate covering 200/400/404 cases

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Implements drag-and-drop tab reordering for instances with optimistic
locking to prevent data loss from concurrent modifications.

Key changes:
- State.Version: monotonically increasing version for conflict detection
- SaveWithVersion: atomic save with version check (returns ErrVersionConflict)
- PATCH /api/instances/reorder: reorder tabs with version validation
- Frontend: HTML5 drag-and-drop + rollback on HTTP 409 Conflict
- Comprehensive concurrent tests covering race conditions (reorder vs start)

The frontend tracks version from GET /api/instances and sends it back
on reorder. If state changed (e.g., another user started an instance),
server returns 409 and client rolls back UI to last confirmed order
before refreshing.

All instance write operations (Start/Stop/Rename/Reorder/etc.) now use
SaveWithVersion. Legacy state.json (no version field) migrates smoothly.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
- Add POST /api/instances/purge endpoint with worktree_id filter
  - Supports per-worktree purge (default) or all worktrees (empty worktree_id)
  - Protected by optimistic locking via version check
  - Returns 409 Conflict with current version on state mismatch
- Add PurgeArchivedInstances(worktreeID, version) to instance manager
  - Atomically removes archived instances for given worktree
  - Cleans up TabOrder for affected worktrees
  - Deletes log files and in-memory state
- Add 4 unit tests covering:
  - Per-worktree purge isolation
  - Version conflict detection
  - TabOrder cleanup across worktrees
  - All-worktrees purge (empty worktree_id)
- Update UI with Purge button in header
  - Filters by current active worktree
  - Optimistic UI update before API call
  - Auto-refresh on 409 conflict
- Add instance_purge to MCP tool list
- Update API docs and CHANGELOG

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
- Add GET /api/worktree/status endpoint for git diff --stat HEAD
- Add Git Changes panel in sidebar bottom with 10s auto-refresh
- Implement smart path truncation with O(1) DOM queries per render
- Add comprehensive unit tests for parseGitDiffStat (8 cases)
- Add concurrency protection with request sequence numbers
- Add resource cleanup on beforeunload and visibilitychange
- Support main repo branch change detection and refresh

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Add API endpoints and UI shortcuts to open worktree directories:
- POST /api/worktrees/open-terminal (uses open -a Terminal)
- POST /api/worktrees/open-finder (uses osascript for reliable activation)

UI/UX:
- Buttons visible only on localhost/127.0.0.1
- Spinner animation during execution
- Prevents duplicate clicks
- 10s client timeout, 5s server timeout

Security:
- Backend enforces loopback boundary via RemoteAddr validation (HTTP 403)
- Refactored common logic into handleWorktreeOpen() helper

Documentation:
- Update PRD.md, ARCHITECTURE.md, API.md

Tests:
- Add TestIsLoopbackHost
- Add TestWorktreeOpenEndpointsRejectNonLoopback

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
- Add internal/monitor package for process stats collection
- Add GET /api/instances/stats API endpoint
- Track connection type (websocket/sse) per instance
- Add resource monitor modal UI with 1s polling
- Group instances by worktree with subtotals and global summary
- Add NOTICE file for third-party license compliance
- Update docs for zero-runtime-dependencies clarification
- Prune stale CPU snapshots to prevent memory leak

License: BSD-3-Clause (gopsutil), MIT, Apache-2.0

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
TTY Size Synchronization:
- Server tracks all connected clients per instance and computes
  minimum (cols × rows) as the shared PTY size
- Add ttyClientHandle with sync.Once for idempotent cleanup
- Limit clients per instance to 8 to prevent resource exhaustion
- Frontend receives resize messages from server and syncs terminal
- Add 4 test cases for TTY size aggregation and limits

Terminal Controls:
- Add refreshCurrentInstance() - disconnects, reloads logs, reconnects
- Add scrollCurrentInstanceToBottom() - quick scroll to latest output
- Use AbortController to cancel in-flight log requests

.gitignore:
- Add myworktree_netgo build artifact

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
- Replace 'Ctrl+C' prompt with interactive 'o' + Enter instruction
- Launch background goroutine to listen for user input
- Allow opening browser at any time after server starts
- Log stdin closure for better debugging

This complements the existing -open flag by providing manual control
without restarting the server.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
- Add beforeunload event handler that triggers browser-native confirmation dialog
- Dialog appears on any page close/refresh/navigation attempt
- Purely client-side UX safeguard — backend instances continue running
- Update API.md, ARCHITECTURE.md, PRD.md with documentation

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
- Change handleMain to return empty branch string instead of HTTP 500
  when git is in detached HEAD state (common in CI shallow clones)
- Update tests to skip or accept empty branch on detached HEAD
- Sync PRD, ARCHITECTURE, and API docs with new behavior

This improves UX in CI/edge cases while maintaining backward compatibility
for normal branch workflows.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
- Replace git diff --stat HEAD with --numstat HEAD for exact
  per-file addition/deletion counts
- Simplify parser from ~130 lines to ~50 lines using fixed TAB-delimited
  format
- Update tests to cover normal, edge, and malformed cases (9 cases)
- Sync API documentation

Benefits:
- Exact counts not limited by terminal width
- Simpler and more robust parsing logic
- Binary files handled uniformly as 0/0

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Copy link
Copy Markdown
Owner Author

@linletian linletian left a comment

Choose a reason for hiding this comment

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

我复核了这次改动,整体方向不错,但目前我认为还有几处会影响正确性/安全性的问题,建议在合并前处理:

  1. git changes 面板存在 DOM XSS 风险。
    renderGitChanges() 直接把 gitChangesErrorc.path 插进 innerHTML。文件名是仓库内容的一部分,属于不可信输入;如果文件名包含引号或 HTML,当前实现会把它当成 HTML 解析。这里建议改成用 DOM API + textContent / setAttribute 构建节点,或者至少先做 HTML escape。

  2. refreshGitChanges() 没有带认证信息,开启 --auth 时轮询会失败。
    页面初始化时已经从 ?token= 提取了 Bearer token,并通过 api() 统一带上;但 refreshGitChanges() 走的是裸 fetch(),没有复用这些 header,也没有把 token 放回 query string。这样开启鉴权后,/api/worktree/status 会持续返回未授权。

  3. reorder / purge 的 409 冲突处理当前实际上不可达。
    api() 对所有非 2xx 响应都会先 throw,但 reorderInstances() / purge 代码随后又判断 res.status === 409。这条分支永远走不到。真实发生 optimistic-lock 冲突时,前端拿不到预期的 rollback / refresh 行为,尤其 reorder 还是 fire-and-forget,容易留下未处理的 rejected promise 和错误的本地顺序。

  4. gitx.GitCommand() 的“超时保护”目前没有真正生效。
    现在只是给 exec.Command() 设置了 WaitDelay,但没有 CommandContext 或其他 deadline/cancel 机制。WaitDelay 不能单独中止仍在运行的 git 进程,所以这些 2s/10s 限制并不能防止 git 卡住。既然这个 PR 明确把这类调用宣传为“带超时保护”,这里建议把实现补成真实超时,避免行为和注释不一致。

- Replace WaitDelay with exec.CommandContext to truly terminate hung git
  processes (fixes issue where git diff could hang indefinitely)
- Fix handleWorktreeStatus to always return HTTP 500 on git failure
  instead of incorrectly returning 200 OK with empty changes
- Refactor frontend API error handling with structured error objects
  carrying status and body for finer-grained error handling
- Improve XSS protection by using textContent/createElement instead of
  innerHTML for rendering git changes
- Add tests for git timeout enforcement and error handling
- Sync API and ARCHITECTURE documentation

Benefits:
- Robust timeout that actually stops hung git processes
- Honest error reporting to users instead of misleading 'no changes'
- Better XSS protection for user-visible git output
- Consistent error handling across the UI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@linletian linletian merged commit c38da45 into develop Mar 23, 2026
2 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.

1 participant