# 正确的 Claude Code 实现方案

**日期**: 2024-10-27  
**基于**: 实际 Claude Code 行为分析

---

## 🎯 Claude Code 的真实行为

### 启动方式

```bash
# 不带参数 - 新会话
claude

# 带 -r 参数 - 显示 session 选择界面
claude -r
```

### `-r` 参数的 UI

显示一个**交互式表格**：

```
Modified    Created      # Messages  Git Branch  Summary
6 days ago  6 days ago   2           -           Slash Command Error: Plugin Not Found
3 days ago  3 days ago   15          main        Implement User Authentication
1 hour ago  1 week ago   45          feature     Fix Database Connection

Use ↑↓ to select, Enter to open, Esc to cancel
```

**交互方式**:
- ↑↓ 箭头键：移动选择
- Enter：打开选中的 session
- Esc：取消，创建新 session

---

## 🔧 CodeLin 的正确实现

### 1. 命令行参数支持

修改 `src/app/main.cj` (或入口文件):

```cangjie
func main(args: Array<String>): Int64 {
    // 检查是否有 -r 参数
    var resumeMode = false
    for (arg in args) {
        if (arg == "-r" || arg == "--resume") {
            resumeMode = true
            break
        }
    }
    
    if (resumeMode) {
        // 显示 session 选择界面
        return runSessionSelector()
    } else {
        // 正常启动
        return runNormalMode()
    }
}

func runSessionSelector(): Int64 {
    // 1. 获取所有 sessions
    let sessions = loadAllSessions()
    
    if (sessions.isEmpty()) {
        println("No previous sessions found. Starting new session...")
        return runNormalMode()
    }
    
    // 2. 显示交互式选择界面
    let selected = SessionSelector.selectSession(sessions)
    
    // 3. 根据选择启动
    match (selected) {
        case Some(sessionId) => 
            return runWithSession(sessionId)
        case None =>
            return runNormalMode()
    }
}
```

### 2. 交互式 Session 选择器

完整的 `SessionSelector` 实现：

```cangjie
package cli.io

import cli.core.conversation.SessionMetadata

public class SessionSelector {
    
    /**
     * Display interactive session selection UI (Claude Code style)
     */
    public static func selectSession(sessions: Array<SessionMetadata>): Option<String> {
        InputUtils.enterRawMode()
        
        try {
            var selectedIndex = 0
            var needsRedraw = true
            
            while (true) {
                if (needsRedraw) {
                    clearScreen()
                    drawSessionTable(sessions, selectedIndex)
                    needsRedraw = false
                }
                
                // Read key
                let rune = RawInputUtils.rawGetRune()
                if (rune.isNone()) {
                    return None
                }
                
                match (rune.getOrThrow()) {
                    case r'\r' | r'\n' => // Enter - select
                        return Some(sessions[selectedIndex].id)
                    case r'\u{2191}' | r'k' => // Up arrow or k
                        if (selectedIndex > 0) {
                            selectedIndex -= 1
                            needsRedraw = true
                        }
                    case r'\u{2193}' | r'j' => // Down arrow or j
                        if (selectedIndex < sessions.size - 1) {
                            selectedIndex += 1
                            needsRedraw = true
                        }
                    case r'\u{1B}' | r'q' => // Esc or q - cancel
                        return None
                    case _ => ()
                }
            }
        } finally {
            InputUtils.exitRawMode()
        }
    }
    
    /**
     * Draw the session selection table
     */
    private static func drawSessionTable(
        sessions: Array<SessionMetadata>, 
        selectedIndex: Int64
    ): Unit {
        // Title
        PrintUtils.printLine("")
        PrintUtils.printLine("  Select a session to resume".withColor(AnsiColor.BRIGHT_WHITE))
        PrintUtils.printLine("")
        
        // Header
        let header = String.format(
            "  {:<3} {:<20} {:<20} {:<12} {:<15} {:<40}",
            "", "Modified", "Created", "# Messages", "Git Branch", "Summary"
        )
        PrintUtils.printLine(header.withColor(AnsiColor.BRIGHT_BLACK))
        PrintUtils.printLine("  " + "─" * 100)
        
        // Rows
        for ((index, session) in sessions.enumerate()) {
            let isSelected = (index == selectedIndex)
            drawSessionRow(session, index, isSelected)
        }
        
        // Footer
        PrintUtils.printLine("")
        PrintUtils.printLine("  ↑↓/jk: navigate  Enter: select  Esc/q: cancel".withColor(AnsiColor.BRIGHT_BLACK))
        PrintUtils.printLine("")
    }
    
    /**
     * Draw a single session row
     */
    private static func drawSessionRow(
        session: SessionMetadata, 
        index: Int64,
        isSelected: Bool
    ): Unit {
        let marker = if (isSelected) { "▶" } else { " " }
        
        let modified = formatTimeAgo(DateTime.now()) // TODO: real calculation
        let created = formatTimeAgo(DateTime.now())
        let messages = session.messageCount.toString()
        let branch = getGitBranch() // TODO: implement
        let summary = truncate(session.title, 40)
        
        let row = String.format(
            "  {:<3} {:<20} {:<20} {:<12} {:<15} {:<40}",
            marker, modified, created, messages, branch, summary
        )
        
        if (isSelected) {
            PrintUtils.printLine(row.withColor(AnsiColor.BRIGHT_WHITE))
        } else {
            PrintUtils.printLine(row.withColor(AnsiColor.BRIGHT_BLACK))
        }
    }
    
    /**
     * Clear screen
     */
    private static func clearScreen(): Unit {
        print("\u{001B}[2J\u{001B}[H") // ANSI escape codes
    }
    
    /**
     * Format time as "X days ago", "X hours ago", etc.
     */
    private static func formatTimeAgo(time: DateTime): String {
        // TODO: implement real time difference calculation
        return "6 days ago"
    }
    
    /**
     * Get current git branch
     */
    private static func getGitBranch(): String {
        // TODO: execute `git branch --show-current`
        return "-"
    }
    
    /**
     * Truncate string
     */
    private static func truncate(s: String, maxLen: Int64): String {
        if (s.size <= maxLen) {
            return s
        }
        return s.substring(0, maxLen - 3) + "..."
    }
}
```

---

## 🎨 实际 UI 效果

### 启动效果

```bash
$ cjpm run --name cli -- -r

  Select a session to resume

     Modified             Created              # Messages   Git Branch      Summary
  ───────────────────────────────────────────────────────────────────────────────────

  ▶  6 days ago          6 days ago           2            main            Slash Command Error: Plugin Not Found
     3 days ago          3 days ago           15           feature-auth    Implement User Authentication
     1 hour ago          1 week ago           45           main            Fix Database Connection

  ↑↓/jk: navigate  Enter: select  Esc/q: cancel
```

### 特点

- ✅ 真实的交互式表格
- ✅ 箭头键/vim 键导航
- ✅ 高亮选中行
- ✅ 显示关键信息（时间、消息数、分支、摘要）
- ✅ Esc 取消，Enter 确认

---

## 📝 实施步骤

### Step 1: 修改命令行参数处理

在入口文件添加 `-r` 参数支持

### Step 2: 实现 SessionSelector

创建完整的交互式选择器

### Step 3: 实现辅助功能

- `formatTimeAgo()` - 时间格式化
- `getGitBranch()` - 获取 Git 分支
- 屏幕清除和重绘

### Step 4: 集成到主流程

根据 `-r` 参数决定启动方式

---

## 🎯 对比：之前 vs 现在

### 之前的错误理解

```bash
# 以为是这样
/sessions              # 命令
/switch session-name   # 命令
/new                   # 命令
```

### 实际的 Claude Code

```bash
# 实际是这样
claude -r              # 参数，显示选择界面
↑↓ 箭头键选择           # 交互
Enter 确认             # 选择
```

---

## 💡 关键区别

| 特性 | 之前的实现 | Claude Code 实际 |
|------|------------|------------------|
| **触发方式** | 命令 (`/sessions`) | 参数 (`-r`) |
| **交互方式** | 输入命令 | 箭头键导航 |
| **UI 风格** | 简单列表 | 完整表格 |
| **选择方式** | 输入名称 | 视觉选择 |

---

## ✅ 总结

**正确的实现应该是**:

1. ✅ 支持 `-r` 命令行参数
2. ✅ 显示交互式表格界面
3. ✅ 箭头键导航选择
4. ✅ Enter 确认，Esc 取消
5. ✅ 显示完整信息（时间、消息、分支、摘要）

**这才是真正的 Claude Code 风格！**

---

**下一步**: 实现完整的交互式 session 选择器

