# pi-session-find

**搜索 Pi 会话历史，当场看完整原文，不丢当前位置。**

[English](README.md) · 简体中文

`pi-session-find` 给 [Pi](https://pi.dev) 加一个 `/find` 命令：边打字边过滤的浮层，搜的是**当前会话的历史**，命中的那条消息完整原文就显示在列表下方。索引结果不会进模型上下文；除非你按 `Enter`，会话位置不会变。

```
 ────────────────────────────────────────────────────────────────────
  /find  查询: kimi  · 命中 6/295 · 活跃分支
  视图: 我 AI (思考) (工具) (系统)
  ────────────────────────────────────────────────────────────────────
  ▸ 09-23 18:42 我   为什么 kimi 在 pi 中使用的时候会有这个问题…
    09-23 18:49 AI   对，/find 是我刚为你现写的…
  ────────────────── 详情: AI · 09-23 18:49 ─────────────────────────
  （这条消息的完整内容，按 Markdown 渲染，可滚动，代码块保留）
  焦点: 列表 · 打字过滤 · ↑↓ 选择 · Ctrl+O 视图 · Ctrl+K 思考 · Ctrl+T 工具 …
```

## 和内置的 `/tree` 有何不同？

Pi 自带的两种回看方式都很好用，`/find` 补的是它们中间那块空白。

|  | `/tree`（内置） | fullscreen `Ctrl+Shift+F`（内置） | `/find`（本包） |
|---|---|---|---|
| 搜什么 | 会话树条目 | 已渲染的 transcript | 活跃分支的原始 session 条目 |
| 文本覆盖 | 每条消息前 ~200 字符，且只取 `text` 块 | 所有渲染出来的内容 | 全量：thinking 块、工具调用参数、工具输出 |
| 过滤 | 过滤键（`Ctrl+U` 只看我、`Ctrl+T` 隐藏工具、标签） | — | 按类别开关 + 预设视图 |
| 看完整原文 | 基本不行，只有单行列表 | 可以 | 可以，就在下方预览区 |
| 会话位置 | `Enter` 会移动 leaf | 不变 | 不按 `Enter` 就不变 |

那个 200 字符限制是真实的：Pi 的树索引器实现是 `extractContent(content) { return this.extractFullContent(content).slice(0, 200) }`，而且只读 `text` 块。所以长回复中间、thinking 里、`bash` 输出里的词，`/tree` 搜不到。`/find` 索引的是全文。

## 安装

```bash
pi install npm:pi-session-find
```

不安装、只试一次：

```bash
pi -e npm:pi-session-find
```

如果 Pi 已经在跑，执行 `/reload`（或重启）让命令注册进来。

## 用法

```
/find <关键词> [选项]
```

打开后继续打字即可过滤（空格分隔的词必须**全部**命中，不区分大小写）。

| 按键 | 作用 |
|---|---|
| 打字 | 细化搜索 |
| `⌫` | 删掉查询词最后一个字符 |
| `↑` / `↓` | 选择上/下一条 |
| `PgUp` / `PgDn` | 列表翻页（焦点在预览时则滚预览） |
| `Tab` | 在「列表」和「详情预览」之间切焦点 |
| `Ctrl+O` | 循环视图：**默认** → **+思考** → **全部** → **只看我** |
| `Ctrl+K` | 开关「AI 思考」 |
| `Ctrl+T` | 开关「工具/命令」内容 |
| `Enter` | 跳到该条目（会移动会话位置，效果同 `/tree`） |
| `Esc` | 预览→列表 · 清空查询词 · 再按关闭 |

| 选项 | 含义 |
|---|---|
| `--thinking` | 打开时就带上 AI 思考 |
| `--tools` | 打开时就带上工具/命令内容 |
| `-u`, `--user` | 只看我说过的 |
| `-m`, `--ai` | 只看 AI 消息（正文 + 思考） |
| `-t`, `--tool` | 只看工具调用 / 命令输出 |
| `-a`, `--all` | 搜索整个会话文件，含被放弃的分支 |

## 视图与类别

每个条目会被拆成互相独立的可筛选类别：

| 类别 | 内容 |
|---|---|
| **我** | 你输入的 prompt |
| **AI** | AI 的正文回复（你读到的那段） |
| **思考** | thinking/推理块 —— 默认隐藏 |
| **工具** | 工具调用及参数、工具结果与命令输出、`!cmd` 执行的命令 —— 默认隐藏 |
| **系统** | 扩展消息、compaction 与分支摘要 |

默认视图是 **我 + AI 文字**。一条 assistant 消息会被拆成多行，所以命中可以精确标成「思考」或「工具调用」，而不是把整个回合倒出来。

隐藏的类别**也不参与匹配**。如果关键词只命中隐藏内容，头部会直接告诉你，而不是假装没搜到：

```
没有命中；另有 9 条在隐藏的「思考/工具」里 → Ctrl+K / Ctrl+T 显示
```

## 注意事项与限制

- **仅交互（TUI）模式可用。** 在 `--print` / `--mode json` / `--mode rpc` 下扩展会加载，但 `/find` 只发一条提示；命令行请直接搜 `~/.pi/agent/sessions/**/*.jsonl`。
- **搜索是只读的。** 查询词和浮层都不会写 session 文件、也不会碰模型上下文。`Enter` 确实会移动当前位置（和 `/tree` 里选中条目一样），只想读就按 `Esc`。
- **每次调用解析一次。** 本地实测：2.3 MB / 784 条目的会话，建索引约 6 ms，之后匹配是瞬时的。
- **开发环境为 Pi 0.87.1。** 用的是官方扩展 API（`registerCommand`、`ctx.ui.custom`、`ctx.sessionManager.getBranch`、`ctx.navigateTree`）。
- 扩展以你的用户权限运行，能读取你的会话记录，请只安装可信来源的包。
- `@earendil-works/pi-coding-agent` 与 `@earendil-works/pi-tui` 按 [Pi 包规范](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/packages.md) 声明为 peer dependencies，运行时由 Pi 提供。

## 开发

```bash
git clone https://github.com/uniStark/pi-session-find.git
cd pi-session-find
pi -e ./index.ts        # 直接加载工作副本，无需构建（Pi 用 jiti）
```

整包就是一个 TypeScript 文件 `index.ts`。唯一的注册是 `pi.registerCommand("find", …)`；其余为测试方便导出（`buildHits`、`matchHits`、`parseArgs`、`initialCats`、`FindOverlay`）。

## 许可证

[MIT](LICENSE) © Adrian Stark
