Session CLI 工具

通过会话管理实现跨调用上下文保持的 CLI 工具开发指南。

Session CLI 工具在多次调用之间保持上下文,无需后台常驻进程。它通过文件在调用之间保存和恢复上下文标识,支持多轮工作流。

阅读本页前,请先了解适用于所有工具类型的通用规范

为什么需要 Session

有些工具的操作是多轮的 —— 每次调用依赖前一次的结果和上下文。以 agent_cursor(Cursor IDE 的 CLI 封装)为例:

# 第一轮:分析代码库
agent_cursor run "分析这个项目的架构" --session main
# Cursor 返回分析结果,同时产生一个 session_id

# 第二轮:基于分析结果继续
agent_cursor run "基于刚才的分析,重构 auth 模块" --session main
# 自动恢复上一轮的 session_id,Cursor 知道「刚才的分析」是什么

如果没有 Session 机制,第二轮调用时 Cursor 完全不知道「刚才的分析」指什么,用户必须手动管理 session_id 并传入 --resume 参数。Session 别名将这个过程自动化了。

Session 和 Daemon 的区别在于:Session 不需要后台常驻进程。工具仍然是「调用即退出」的,只是在调用之间通过文件保存和恢复上下文标识。

架构概览

第一次调用:
┌─────────┐    参数    ┌───────────┐    结果 + session_id    ┌──────────────┐
│  调用方  │  ──────►  │  CLI 工具  │  ──────────────────►   │  输出        │
│          │           │           │                         │              │
└─────────┘           └─────┬─────┘                         └──────────────┘
                            │ 保存
                            ▼
                    ~/.tool/sessions/main.json

后续调用:
┌─────────┐    参数    ┌───────────┐    结果    ┌──────────────┐
│  调用方  │  ──────►  │  CLI 工具  │  ──────►  │  输出        │
│          │           │  自动恢复  │           │              │
└─────────┘           └─────┬─────┘           └──────────────┘
                            │ 读取
                            ▲
                    ~/.tool/sessions/main.json

项目结构

agent_cursor/
├── main.go
├── go.mod
├── cmd/
│   ├── root.go           # 根命令、全局 --session 标志
│   ├── skill.go          # skillSpec 常量
│   ├── run.go            # 执行命令(自动 resume)
│   └── session.go        # session ls / show / rm 子命令
└── internal/
    ├── output/
    │   └── output.go
    └── session/
        └── session.go    # session 持久化逻辑

Session 数据结构

type SessionData struct {
    Name      string    `json:"name"`
    SessionID string    `json:"sessionId"`
    CWD       string    `json:"cwd"`
    CreatedAt time.Time `json:"createdAt"`
    UpdatedAt time.Time `json:"updatedAt"`
}

Session 文件存储在 ~/.agent_cursor/sessions/<name>.json,文件名即为 Session 别名。

全局 --session 标志

通过 PersistentFlags 注册,使所有子命令都能使用 Session:

func init() {
    rootCmd.PersistentFlags().StringVarP(&sessionName, "session", "s", "",
        "Session alias name for automatic resume")
    rootCmd.PersistentFlags().StringVar(&cwdPath, "cwd", "",
        "Working directory for Cursor agent (default: current directory)")
}

Session 自动恢复

在命令执行时自动检查并恢复会话,用户无需感知 session_id 的存在:

if sessionName != "" && resumeID == "" {
    sess, err := session.Load(sessionName)
    if err == nil && sess.SessionID != "" {
        effectiveResumeID = sess.SessionID
    }
}

// 执行完成后保存 session
if sessionName != "" && result.SessionID != "" {
    session.Save(sessionName, result.SessionID, cwd)
}

Session 子命令

提供 session 子命令组,让用户查看和管理已有会话:

agent_cursor session ls              # 列出所有会话
agent_cursor session show <name>     # 查看会话详情(session_id、创建时间等)
agent_cursor session rm <name>       # 删除会话

开发检查清单

  • 通用规范中的所有基础要求
  • 全局 --session 标志
  • Session 数据持久化到文件(~/.tool/sessions/
  • 命令执行时自动恢复 Session
  • 命令执行后自动保存 Session
  • session ls / session show / session rm 管理子命令
  • --skill 中说明 Session 的使用方式和多轮交互流程