Skip to content

feat(terminal): 添加复制 tmux 恢复命令功能#422

Merged
J3n5en merged 1 commit into
J3n5en:mainfrom
zwmmm:feat/terminal-tmux-copy-command
Apr 11, 2026
Merged

feat(terminal): 添加复制 tmux 恢复命令功能#422
J3n5en merged 1 commit into
J3n5en:mainfrom
zwmmm:feat/terminal-tmux-copy-command

Conversation

@zwmmm

@zwmmm zwmmm commented Apr 11, 2026

Copy link
Copy Markdown
Contributor

Summary

  • 当终端存在 tmux session 时,在右键菜单中新增"复制 tmux 恢复命令"选项
  • 方便用户快速复制 tmux -L enso attach-session -t <session> 命令

Test plan

  • 在终端无 tmux session 时,右键菜单不显示"复制 tmux 恢复命令"
  • 在终端有 tmux session 时,右键菜单显示"复制 tmux 恢复命令"
  • 点击后命令已复制到剪贴板

🤖 Generated with Claude Code

@github-actions

This comment has been minimized.

当终端存在 tmux session 时,在右键菜单中新增"复制 tmux 恢复命令"选项。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@zwmmm zwmmm force-pushed the feat/terminal-tmux-copy-command branch from c96afaf to 495c4e5 Compare April 11, 2026 10:54
@github-actions

github-actions Bot commented Apr 11, 2026

Copy link
Copy Markdown
Contributor

Claude finished @zwmmm's task in 2m 29s —— View job


🔍 代码审查报告

👋 欢迎查看审查结果! 本次审查已完成,以下是详细分析和建议。
💡 使用提示:点击 📁 文件链接可直接跳转到代码位置,建议按优先级处理问题。

📊 审查概览 · 一目了然

📋 审查项目 🔢 发现数量 📈 占比 🎯 处理状态
📁 审查文件 2 100% 已完成
🚨 严重问题 0 0% 🟢
⚠️ 中等问题 1 33% 🟡 建议处理
轻微问题 2 67% 🔵 后续优化

🏆 代码质量评分

📊 综合评分: 88/100  🌟🌟🌟🌟⭐
📋 本次等级: 良好

📋 问题分布

🚨 严重: ░░░░░░░░░░  0%
⚠️ 中等: ███░░░░░░░ 30%
⚡ 轻微: █████░░░░░ 50%
总体评分: ⭐⭐⭐⭐☆ (4.4/5)

🎯 关键发现

🏷️ 类别 🔍 发现数量 🎯 优先级 📈 趋势
🔒 安全性 0 个 🟢 无 ✅ 良好
🎨 UX 体验 1 个 🟡 中 📊 可优化
🧪 健壮性 2 个 🔵 低 📉 可改善

✅ 亮点总结

  • 🎯 功能聚焦:改动仅 16 行,职责单一,修改范围克制
  • 🛡️ 安全可靠tmuxSessionName 在生成时已经通过 .replace(/[^a-zA-Z0-9_-]/g, '_') 清洗(见 src/renderer/components/chat/AgentTerminal.tsx:430-433),拼接到恢复命令中不存在 shell 注入风险
  • 🧱 正确使用 ReftmuxSessionNameRefuseRef,无需加入 useCallback 依赖数组,未错误触发重渲染
  • 🌐 国际化规范:i18n 以英文 key 为源、zhTranslations 补中文翻译,key 命名与既有约定一致
  • 🧹 菜单结构清晰:使用 separator-2 避免与既有 separator-0/1 冲突,条件展开 ...(... ? [...] : []) 保持空菜单不留残余分隔符

🐛 问题清单与修复指南 · 📋 点击展开查看

📋 👆 点击此处展开详细问题列表 (共 3 个问题)

🚀 快速开始


⚠️ 中等级别 (Major) 建议修复

🟡 #1 src/renderer/components/chat/AgentTerminal.tsx:922-927

🏷️ 类型: UX 体验缺失 | ⏰ 优先级: P1 - 本版本修复 | 🎯 影响范围: 交互反馈

  • 🔍 问题描述:点击"复制 tmux 恢复命令"后没有任何可见反馈,用户无法确认命令是否复制成功。终端原生的"复制"选择内容能通过选区消失感知,但这个新菜单项在命令写入剪贴板后没有任何提示(成功与失败都静默)。

  • 📋 代码片段

    // src/renderer/components/chat/AgentTerminal.tsx:922-927
    case 'copyTmuxRestore':
      if (tmuxSessionNameRef.current) {
        const restoreCmd = `tmux -L enso attach-session -t ${tmuxSessionNameRef.current}`;
        navigator.clipboard.writeText(restoreCmd);
      }
      break;
  • 🛠️ 解决方案:建议借助项目中已有的 toast/notification 机制给出"已复制"提示,同时对 writeText 返回的 Promise 做基础的错误捕获:

    // src/renderer/components/chat/AgentTerminal.tsx:922-927
    case 'copyTmuxRestore':
      if (tmuxSessionNameRef.current) {
        const restoreCmd = `tmux -L enso attach-session -t ${tmuxSessionNameRef.current}`;
        navigator.clipboard
          .writeText(restoreCmd)
          .then(() => toast.success(t('Copied to clipboard')))
          .catch((err) => {
            console.error('Failed to copy tmux restore command', err);
            toast.error(t('Failed to copy'));
          });
      }
      break;
  • ⚠️ 潜在影响:用户可能重复点击菜单或以为功能没生效,降低新特性的感知价值

  • 🔗 Fix this →


⚡ 轻微级别 (Minor) 优化建议

🔵 #2 src/renderer/components/chat/AgentTerminal.tsx:880-888

🏷️ 类型: 代码复用/可维护性 | ⏰ 优先级: P2 - 后续版本 | 🎯 影响范围: 局部

  • 🔍 问题描述:菜单项构造和 switch 分支中的 tmux 恢复命令字符串硬编码了两处:一次在 handleContextMenu 中,另一次在构建 tmux session 的 finalCommand 中(src/renderer/components/chat/AgentTerminal.tsx:440)。如果未来 tmux -L enso 的 socket name 发生变化,需要在多处同步修改,容易遗漏。

  • 📋 代码片段

    // src/renderer/components/chat/AgentTerminal.tsx:440
    finalCommand = `env -u TMUX tmux -L enso -f /dev/null new-session -A -s ${tmuxSessionName} '${escaped}'`;
    
    // src/renderer/components/chat/AgentTerminal.tsx:924
    const restoreCmd = `tmux -L enso attach-session -t ${tmuxSessionNameRef.current}`;
  • 🛠️ 解决方案:建议抽一个常量或工具函数统一 tmux socket name:

    // src/renderer/components/chat/AgentTerminal.tsx (file top or shared util)
    const TMUX_SOCKET_NAME = 'enso';
    const buildTmuxAttachCommand = (sessionName: string) =>
      `tmux -L ${TMUX_SOCKET_NAME} attach-session -t ${sessionName}`;

    然后在两处引用同一常量/函数。

  • ⚠️ 潜在影响:维护性略弱,但当前影响面很小


🔵 #3 src/renderer/components/chat/AgentTerminal.tsx:930

🏷️ 类型: Hook 依赖一致性 | ⏰ 优先级: P2 - 后续版本 | 🎯 影响范围: 局部

  • 🔍 问题描述:这是一个预先存在的潜在问题,并非本 PR 引入,但本次改动使用了 tmuxSessionNameRef,可以顺带确认:useCallback 的依赖数组未覆盖 onSplit/onMerge/onFocus 的所有捕获情况之外,如果以后某次扩展误把 非 ref 值(例如一个 state)引入此回调而忘记加到依赖,可能会捕获到陈旧值。

    由于本次新增的 tmuxSessionNameRef.current 确实是 ref,本 PR 本身没有问题。此条仅作为提醒,无需在本 PR 修复。

  • 🛠️ 建议:可以考虑在文件内追加一条 // eslint-disable-next-line react-hooks/exhaustive-deps 的注释并解释原因,或者启用 exhaustive-deps 规则来帮助捕获未来的回归。

  • ⚠️ 潜在影响:无当前影响,仅为可维护性建议


📊 修复优先级矩阵

🎯 优先级 🚨 严重 ⚠️ 中等 ⚡ 轻微 📈 总计
🔴 P0 0 个 - - 0 个
🟡 P1 - 1 个 - 1 个
🔵 P2 - - 2 个 2 个
📊 合计 0 1 2 3 个

🧪 Test plan 补充建议

PR 描述中的测试点已经覆盖了主要场景,建议补充:

  • 非 Claude agent / Windows 平台:确认 tmuxSessionNameRef.currentnull,菜单项不显示
  • 复制后粘贴验证:在外部终端粘贴命令,确认能正确 attach 回会话
  • 会话结束后:当 tmux session 被 kill 后(触发 killSession),tmuxSessionNameRef.current 是否仍保留旧值导致菜单项继续显示?建议在 killSession 调用后同步将 ref 置为 null
  • 多终端分屏场景:在 split 的多个终端上各自右键,复制的命令是否对应各自独立的 session 名

🎯 合并决策建议

📋 合并评估结果

📊 评估维度 ⭐ 得分 🎯 状态 💭 说明
🔐 安全性 10/10 ✅ 通过 session name 已清洗,无注入风险
📊 代码质量 9/10 ✅ 优秀 风格一致、改动克制
⚡ 性能影响 10/10 ✅ 无影响 仅菜单构造时多一次 ref 读取
🛠️ 功能完整性 8/10 ⚠️ 部分 缺少复制成功的用户反馈
🧪 测试覆盖 7/10 ⚠️ 基本 仅人工 Test plan,无自动化用例

📈 综合评分: 44/50 分 · 等级: 良好


🚦 最终建议

建议合并

📝 详细理由

  • 🟢 代码质量高,实现简单直接,无严重或中高风险问题
  • 🟢 安全检查通过:tmux session name 在源头已做字符白名单清洗
  • 🟢 符合项目既有模式(i18n key 用英文、菜单条目结构、ref 使用方式)
  • 🟡 唯一的中等问题(fix: 彻底修复终端渲染问题(花屏和字体设置闪烁) #1 无复制反馈)不阻塞合并,但建议在本版本内补上 toast 提示以提升用户体验
  • 🔵 其余两条为可选优化,可延后处理

🎯 具体行动建议

  1. 建议合并前完成(可选)

  2. 后续版本改进


· 分支:feat/terminal-tmux-copy-command

@J3n5en J3n5en merged commit 2cb8d69 into J3n5en:main Apr 11, 2026
1 check passed
@zwmmm zwmmm deleted the feat/terminal-tmux-copy-command branch April 11, 2026 13:36
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