Skip to content

Latest commit

 

History

History
345 lines (264 loc) · 13.2 KB

PRD.md

File metadata and controls

345 lines (264 loc) · 13.2 KB

PRD — Nexus AI 终端面板

版本: v1.0.0 状态: Complete 锚点: docs/NORTH-STAR.md 最后更新: 2026-07-15


Problem Statement

开发者需要一个统一入口,让 AI Agent 能在任意项目目录中持续运行,并能在 PC、手机、IM 等任意渠道随时介入——现有工具(ttyd、SSH)在移动端控制字符输入残缺,且缺乏针对 AI Agent 生命周期的管理界面和异步交互能力。


Target Users

用户即开发者本人(单用户/个人服务器)

  • 同时跑多个 Claude Code Agent,需要随时从任意设备查看进度、发送指令
  • 外出时通过手机/Telegram 给 AI 下任务,回家后在 PC 上接续
  • 不想保持 SSH 连接,关掉浏览器后 Agent 继续运行

Core Features

Must(v1 Complete)

ID Feature 验收标准
F-01 WebSocket tmux 桥接 浏览器关闭后 tmux 和 Agent 继续运行;重新打开可接续
F-02 JWT 单密码认证 密码 bcrypt hash 存 env,Token 30天有效
F-03 xterm.js 终端渲染 256色/TrueColor/Unicode;scrollback 10000行
F-04 移动端控制字符工具栏 可发送 Esc/Tab/Ctrl+C/方向键等;触摸不弹软键盘
F-05 移动端滚动与缩放 单指滑动浏览历史;双指捏合调字号(8–32px)
F-06 Session 管理 API POST/GET/DELETE /api/sessions;tmux 新建/切换/关闭 window
F-07 工具栏服务端持久化 配置存 data/toolbar-config.json(volume),跨设备共享
F-08 PWA 支持 manifest.json + Service Worker,可添加主屏幕
F-12 claude -c 会话续接 自动检测 .claude-data/.claude,claude -c 续接历史会话

Should(v1 Complete)

对应北极星「轴三:极致 Agent 管理体验」

ID Feature 验收标准
F-09 Tab Bar UI 顶部实时显示所有 tmux window,点击切换,活跃 tab 高亮
F-10 移动端底导航 底部 Tab 快速切换 window,支持新建;覆盖顶部 Tab Bar
F-11 独立 window PTY ensurePty(windowId) Map;/ws?window=N 多设备不互扰
F-15 Agent 状态卡片 每个 window 显示最后输出摘要(是否在跑/是否等待输入)

Could(v1 Complete)

对应北极星「轴二:零摩擦上下文同步」——不限于浏览器终端的交互渠道

(F-13/F-14/F-16/F-17 已移除 — 非交互派发、上下文附件、Telegram Bot、多渠道路由已从代码库中移除。2026-10 曾由 F-22 微信通道 以更小的形态重新引入;2026-10-01 该通道整体迁出本仓库,成为独立项目 ~/work/wechat-agent(独立 git 仓库、PM2 名 wechat-agent、自带 profile 与凭证)。

Nexus 侧不再持有任何微信代码:本仓库与微信通道零耦合(server.js 全程未引用过它)。唯一残留的关联是显示层——通道日志所在的 tmux 窗口由 Nexus 的 PTY/WS 通路呈现,但这对 Nexus 而言与任意其它窗口无异。

Done(原 Nice/v4 — 已提前完成)

对应北极星「轴一:零配置启动」——消灭一切不必要的决策步骤

ID Feature 验收标准
F-19 项目-窗口两级结构 项目 = 目录,窗口 = 同目录标签。新建项目时选目录;新窗口自动继承当前目录;消灭「每次新建都要选目录」的重复操作
F-20 统一会话管理界面 借鉴 Slack Workspace/Channel 模式:项目列表(下部)+ 窗口列表(上部),新建按钮分区放置,视觉层次清晰

Feature Detail: 项目-窗口两级结构(F-19)

问题:当前每次新建 window 都要选目录,而用户心智模型是「项目=目录,窗口=同目录下的多个标签」。

解法:利用 tmux session 环境变量存储项目目录,实现「新建项目选目录,新建窗口自动继承」。

POST /api/windows
  body: { rel_path?, shell_type?, profile? }

  场景 1 - 新项目(提供 rel_path):
    → tmux set-environment NEXUS_CWD <dir>
    → tmux new-window -c "$dir"

  场景 2 - 新窗口(不提供 rel_path):
    → cwd=$(tmux show-environment NEXUS_CWD | cut -d= -f2)
    → tmux new-window -c "$cwd"

交互:

  • Sidebar 「+」按钮拆分为二级菜单:「📁 新项目」/「➕ 新窗口」
  • 「新项目」→ 弹出 WorkspaceSelector 选目录
  • 「新窗口」→ 直接创建,继承当前项目目录

心智模型:

  • 项目 = 目录(首次需要指定)
  • 窗口 = 同目录下的多个终端标签(自动继承目录)

Feature Detail: 统一会话管理界面(F-20)

核心映射:直接使用 tmux 原生概念,前端映射更易理解

  • tmux session → Project(工作目录,环境隔离)
  • tmux window → Channel(终端标签,共享目录)

设计灵感:Slack 的 Workspace/Channel 两层导航结构

  • Channel 列表(上部):当前 Project 下的多个终端窗口
  • Project 列表(下部):不同的工作目录(每个对应一个 tmux session)

界面布局

┌─────────────────────────────┐
│  会话管理              [×]   │
├─────────────────────────────┤
│                             │
│  📂 nexus ~/work/nexus      │  ← 标题:当前 Project 名+路径
│  ─────────────────────────  │
│  #general        ●         │  ← Channel 列表(tmux windows)
│  #backend        ○         │
│  #test          ⏳         │
│                             │
│  [+ 新 Channel]            │  ← 在下方,靠近 Channel 列表
│                             │
│  ═════════════════════════  │  ← 粗分隔线
│                             │
│  📁 Projects               │
│  ● nexus           (3)     │  ← Project 列表(tmux sessions)
│  ○ my-app          (1)     │
│  ○ backend-api     (2)     │
│                             │
│  [+ 新 Project]            │  ← 在下方,靠近 Project 列表
│                             │
└─────────────────────────────┘

关键设计决策

概念 对应 说明
Project tmux session 每个 session 独立环境变量,有自己的 NEXUS_CWD
Channel tmux window 同 session 内的多个窗口,共享工作目录
激活态 active session/window 高亮显示当前所在的 project 和 channel

状态指示

Channel 列表项(带 # 前缀):
  #general      ●    ← 绿色点 = 运行中
  #backend      ○    ← 灰色点 = 空闲
  #deploy      ⏳    ← 黄色点 = 等待输入
  #shell       💤    ← 灰色 = shell 状态

Project 列表项:
  ● nexus      (3)   ← 蓝色高亮 = 当前激活,(3)=3个channel
  ○ my-app     (1)   ← 未激活,有1个channel
  ○ backend-api (2)  ← 未激活,有2个channel
  ○ legacy          ← 无括号 = 该session没有窗口(异常)

API 设计(简化版)

GET  /api/projects                → 列出所有 tmux sessions(Project 列表)
GET  /api/projects/:name/channels → 列出指定 session 的所有 windows(Channel 列表)

POST /api/projects                → 新建 Project
  body: { name, path, shell_type, profile? }
  → tmux new-session -d -s <name> -c <path>
  → tmux set-environment NEXUS_CWD <path>

POST /api/projects/:name/channels → 新建 Channel
  body: { shell_type, profile? }
  → 在当前 session 内 tmux new-window -c "$NEXUS_CWD"

POST /api/projects/:name/activate → 切换到指定 Project
  → 切换 active tmux session(attach-client 或设置 target)

POST /api/channels/:index/attach  → 切换到指定 Channel(已有接口)
DELETE /api/channels/:index       → 关闭 Channel(已有接口)

交互流程

1. 新建 Project

点击「+ 新 Project」
  → 弹出 WorkspaceSelector 选择目录
  → 用户输入 Project 名称(默认目录名)
  → POST /api/projects { name: "my-app", path: "/home/libra/work/my-app" }
  → tmux new-session -d -s my-app -c /home/libra/work/my-app
  → tmux set-environment -t my-app NEXUS_CWD /home/libra/work/my-app
  → 在该 session 创建第一个 window(自动命名为 #general 或目录名)
  → 自动切换到新 Project(Project 列表更新,Channel 列表加载)

2. 新建 Channel

点击「+ 新 Channel」
  → 检查当前是否有激活 Project
  → POST /api/projects/:name/channels { shell_type, profile }
  → 在当前 session 内创建新 window
  → 自动继承该 session 的 NEXUS_CWD
  → Channel 列表更新,自动切换到新 Channel

3. 切换 Project

点击 Project 列表中的某项
  → 设置该 session 为 active
  → Channel 列表区域刷新:显示该 Project 的所有 Channel
  → 自动切换到该 Project 的 active window(或第一个 window)
  → 终端 WebSocket 重连到新的 session:window

4. 切换 Channel

点击 Channel 列表中的某项
  → POST /api/channels/:index/attach
  → 同现有行为:切换到该 window

Channel 命名规则

第一个 Channel(创建 Project 时):
  - 默认:目录名(如 nexus)
  - 或:#general

后续 Channels:
  - 默认:目录名-序号(如 nexus-1, nexus-2)
  - 用户可重命名(重命名 tmux window)

空状态处理

无任何 Project 时:

Channel 列表区域:
  「没有活跃的 Project」

Project 列表区域:
  「暂无 Projects」
  [+ 创建第一个 Project]

当前 Project 无 Channel(异常情况):

Channel 列表区域:
  "📂 nexus ~/work/nexus"
  「该 Project 没有 Channel」
  [+ 创建第一个 Channel]

向后兼容

  • 现有 tmux session 直接显示为 Projects(name 作为 project name)
  • 现有 windows 显示为 Channels
  • 首次打开界面时,为当前 session 尝试读取 NEXUS_CWD
    • 如果未设置,提示用户「为当前 Project 设置工作目录」
    • 或自动设置为 WORKSPACE_ROOT

视觉设计

/* Channel 列表区域(上部)*/
- 标题栏:"📂 {project.name} {cwd路径}"(cwd 用灰色小字)
- Channel 项:"#{name}" 前缀(Slack 风格)
- 状态点:跟在名字后面
- +按钮:在区域底部,样式与列表项对齐

/* Project 列表区域(下部)*/
- 标题栏:"📁 Projects"
- 背景:var(--nexus-bg2) - 稍暗,与 Channel 区形成层次
- Project 项:简洁显示,名称 + 右侧 channel 计数
- +按钮:在区域底部

/* 分隔线 */
- Channel 区标题下:1px solid var(--nexus-border)
- 两区域之间:2px solid var(--nexus-border)

数据结构(前端状态)

// 不再需要独立的 projects.json
// 直接从 tmux 读取

interface Project {
  name: string;           // tmux session name
  path: string;           // NEXUS_CWD (tmux show-environment)
  active: boolean;        // 是否是当前 active session
  channelCount: number;   // window 数量
}

interface Channel {
  index: number;          // tmux window index
  name: string;           // tmux window name
  active: boolean;        // 是否是该 session 的 active window
  status: 'running' | 'idle' | 'waiting' | 'shell'; // 状态推断
}

Feature Detail: 会话一键恢复(Chrome-style)

宕机/崩溃后(tmux server 或 Nexus 进程死亡):

  • Nexus 启动时自动恢复上次快照的所有 projects/channels,并 resume 每个 channel 的 claude 对话;启动竞态失败时,前端可一键手动恢复。
  • 快照选择器拒绝崩溃后的近空快照(无 claude 频道的快照不参与恢复),自动回退到最新 含频道的一份。
  • 恢复全程幂等只增:已存在 session/window 跳过,不覆盖正在运行的会话;已在跑 claude 的频道不会被重复注入。
  • 入口:Settings → 会话恢复「恢复会话」按钮(带 hover/行内说明);项目列表为空且有待 恢复标记时的「一键恢复?」横幅。
  • 严格 gating:boot 检测到崩溃写 data/restore-pending.json,恢复完成即清除;仅「崩溃过且 仍有缺失」时可点,平时按钮置灰(available = pending && 有富快照)。 实现见 docs/SESSION-PERSISTENCE.md §11。

Success Metrics

Metric Target
移动端 Esc/Ctrl+C 发送成功率 100%
浏览器重连后终端恢复时间 < 2s
工具栏配置跨设备同步 重连后自动加载
PWA 添加主屏并可用 iOS Safari / Android Chrome

Out of Scope

  • 多用户/团队功能、注册系统、权限管理
  • 替换 tmux(持久化/scrollback 继续由 tmux 负责)
  • 通用 Web SSH 工具(不针对 claude CLI 工作流的功能不做)
  • Session 数据库(JSON 文件 + tmux 实时读取)
  • Docker socket 暴露给前端

Known Limitations(v1)

问题 影响 解法
多客户端 resize 冲突 多设备同时连接时 PTY 尺寸以最后收到的为准 直接使用当前客户端尺寸