# Clavue v8.10.16 — Release Notes

**发布日期**：2026-05-15
**npm**：`clavue@8.10.16`
**GitHub**：https://github.com/mycode699/clavue/releases/tag/v8.10.16
**升级命令**：

```bash
npm install -g clavue@8.10.16
# 或一次性：
npx -y clavue@8.10.16
```

---

## TL;DR

8.10.16 是个 bug-fix patch，修两个困扰 `--resume` 的真问题：

1. **`clavue --resume <uuid>` 现在能跨项目目录工作**。之前 `loadSessionFile(sessionId)` 只在当前 cwd 对应的 `~/.clavue/projects/<slug>/` 下找 `<uuid>.jsonl` —— 在外接盘 / 别的项目目录里跑这个会话就拿到 `No conversation found with session ID: <uuid>`，UUID 完全正确也不行。修复后，本地路径 stat 失败时扫所有 sibling project dirs，UUID 全局唯一所以第一命中就是对的。
2. **`clavue --resume <bad-uuid> "prompt"` 不再静默吞 prompt**。之前如果 UUID 拼错（多/少一个字符），`validateUuid` 拒绝后交互模式 fallthrough 到 picker，把无效 UUID 当 search term 喂进去（picker 显示 0 hit），同时 positional `prompt` 完全丢弃。用户看到的现象就是"中断 + 没反馈"。修复后两条 stderr 警告：`looks-like-uuid 但 validateUuid 拒绝` + `picker 路径会丢弃 prompt argument`。

测试：1301 / 1298 pass / 3 skipped / 0 fail（`npm run check`, ~59s）。

---

## 1. Cross-project resume by UUID

### 问题

复现：

```bash
# session 实际写在外接盘
ls ~/.clavue/projects/-Volumes-MobileDrive------------cmux-sq1yoq/3fe5d22e-9c61-4b3f-8147-02fc2dacb64f.jsonl  # exists, 5.5 MB

# 在另一个项目目录尝试 resume
cd /Users/lu/codebase/claude-code-source
clavue --resume 3fe5d22e-9c61-4b3f-8147-02fc2dacb64f -p "..."
# → No conversation found with session ID: 3fe5d22e-9c61-4b3f-8147-02fc2dacb64f
```

`getLastSessionLog(sessionId)` → `loadSessionFile(sessionId)`：

```ts
const sessionFile = join(
  getSessionProjectDir() ?? getProjectDir(getOriginalCwd()),
  `${sessionId}.jsonl`,
)
return loadTranscriptFile(sessionFile)
```

只看一个固定路径。session 不在那里就直接返回空 → 上层报 not found。但 `loadAllProjectsMessageLogs*` 已经存在并扫了所有 project dirs（picker 用得到），只是按 UUID 直查的 fast path 没用它。

### 修复

新增 `resolveSessionFilePath(sessionId)`（`src/utils/sessionStorage.ts`）：

1. 先 stat `getSessionProjectDir() ?? getProjectDir(getOriginalCwd())` 下的 `<uuid>.jsonl` —— 命中就返回（fast path，不变）。
2. miss 就 readdir `~/.clavue/projects/`，对每个 sibling dir 试 stat `<dir>/<uuid>.jsonl`，第一命中就返回。UUID 全局唯一，不存在歧义。
3. 全 miss 时返回本地路径让 loader 自然报错（保留旧行为，错误信息不变）。

`loadSessionFile` 和 `getLastSessionLog` 都改用它。同时 `getLastSessionLog` 返回的 `LogOption.fullPath` 也改成 resolved path —— 这一步重要：下游 `recordTranscript` / `copyPlanForResume` / `copyFileHistoryForResume` 都用这个 fullPath 写盘，否则 cross-project resume 后续操作会写到错的 project dir。

### 改动文件

- `src/utils/sessionStorage.ts:4049-4112` — `resolveSessionFilePath` + `loadSessionFile` 改造
- `src/utils/sessionStorage.ts:4142-4205` — `getLastSessionLog` 用 resolved path

### 兼容性

- 同项目 resume：fast path 不变，性能无回归（一次 stat 命中）。
- 不存在的 UUID：fallback 扫描后仍 miss，返回原本的 "No conversation found" 错误。
- 同一 UUID 出现在多个 project dirs：`readdir` 顺序为准，取第一命中。这种情况只出现在 `cp -r` 复制了 session 文件的边缘场景，本来就 ill-defined。

---

## 2. Loud failure for invalid `--resume` value with prompt

### 问题

```bash
clavue --resume 3fe5d22e-9c61-4b3f-8147-02fc2dacb64fe /Users/lu/codebase/1.md
#                                                  ^^^ 37 chars, UUID 是 36
```

commander 解析为：
- `options.resume = "3fe5d22e-...64fe"`（invalid UUID，37 字符）
- `prompt = "/Users/lu/codebase/1.md"`

代码路径（`src/main.tsx:4558+`）：
1. `validateUuid` → null。
2. 当 custom title fallback：`searchSessionsByCustomTitle` exact 0 hit → 把它当 `searchTerm` 给 picker。
3. picker 弹出，搜索 `3fe5d22e-...64fe`，0 hit。
4. **`prompt` 完全没传给 picker 路径**：`launchResumeChooser` 不收 initial prompt，REPL 也不会把它当用户消息发出去。

用户看到：picker 出来空空的，选了一个会话后 prompt 没了。看起来"中断 + 发送指令没反馈"。

### 修复

picker fallthrough 之前两条 stderr 警告（`src/main.tsx:5081+`）：

- 当 `--resume` value 形如 UUID（含 `-`、长度 30-40、hex）但 `validateUuid` 拒绝 → 提示 `Standard UUIDs are 36 characters: 8-4-4-4-12 hex digits.`
- 当用户同时给了 prompt argument → 提示 `prompt argument "..." is ignored on the resume picker path. Pick a session, then send the prompt from the REPL.`

silent failure 变响。用户立刻看到 root cause（多打了一个字符 / 不该把文件路径放在 `--resume` 之后），不再误以为 CLI hang 了。

注：picker 路径下把 prompt 透传给选完后的会话作为 initial message 是更彻底的修法，但跨整个 ResumeConversation 的 launchRepl flow，scope 偏大，留给下一个版本。

### 改动文件

- `src/main.tsx:5080-5113` — picker 入口前的 stderr 警告

---

## 3. 升级路径

```bash
npm install -g clavue@8.10.16
# 或：
npx -y clavue@8.10.16
```

无破坏性变更：

- `--resume` CLI 形态不变。
- 同项目 resume 行为完全不变（fast path 保持）。
- 跨项目 resume 从"必失败"变成"工作"，纯增强。
- Invalid UUID 从"silent + 吞 prompt"变成"warn + 进 picker"，纯增强。

---

## 4. Tests / Verify

```
npm run check
# tests 1301
# pass 1298
# skipped 3
# fail 0
# duration_ms ~59s
```

无新增测试 —— 这是 surgical bug fix，已被现有 sessionStorage / resume 套件覆盖。新行为靠手动 e2e：

```bash
# A: 跨项目 UUID resume
cd /Users/lu/codebase/claude-code-source
clavue --resume <session-uuid-from-other-project> -p "reply OK"
# → 现在能找到并 resume

# B: invalid UUID + prompt
clavue --resume 3fe5d22e-9c61-4b3f-8147-02fc2dacb64fe /tmp/x.md
# → 两条 stderr warning 出现，picker 仍弹出
```

---

## 5. 改动文件清单

| 文件 | 性质 |
|---|---|
| `src/utils/sessionStorage.ts` | 新增 `resolveSessionFilePath`；`loadSessionFile` + `getLastSessionLog` 改用它；`LogOption.fullPath` 用 resolved path |
| `src/main.tsx` | picker fallthrough 前 stderr 警告 invalid UUID + dropped prompt |
| `src/constants/branding.ts` | APP_VERSION_FALLBACK → 8.10.16 |
| `package.json` | 8.10.15 → 8.10.16 |
| `README.md` | 版本号同步 |
| `content-artifacts/llms.txt` | 同步到 8.10.16 |
| `content-artifacts/llms-full.txt` | 同步到 8.10.16 |

---

## 6. 后续提示

- picker 路径透传 prompt argument 作为 initial message 是 8.10.16 之后第一个候选优化（需要在 `ResumeConversation` 的 props 里加 `initialUserPrompt: string`，并在 `onSelect` 后通过 REPL 的 initialMessage 注入）。
- `resolveSessionFilePath` 当前是 stat-per-dir 串行扫描，project dirs 通常 <100 个，体感无感知；若将来项目目录爆炸到上千级别，可换 in-memory index。
