npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

midflight-replay

v0.1.2

Published

Turn a finished AI coding-agent session into a scrubbable, single-file HTML replay you can attach to a PR. Zero deps, zero build, zero network.

Readme


看它动起来

本机一条真实 Claude Code 会话——原始 JSONL 31 MiB,解析出 3,111 步,10 次第一手压缩事件——压进 16 秒回放。不是 mock 数据,也不是手写 demo 素材:视频里的文件就是 midflight replay 对着一条真实会话日志跑出来的。

画面里的每个数字都可复现:

  • 左侧主轴是 3,111 步里显示的 3,000 步;抽稀横幅直接写明,不假装文件是完整的
  • 绿色面积是上下文锯齿:每轮对话往上爬,宿主压缩时掉下来。其中 10 次标了 ⇣ 第一手压缩事件
  • 右侧是一次真实 Edit 的 before-image,能看到 agent 实际打进去的补丁,带行号
  • 覆盖度条显示 52%:那条会话 244 处编辑里只有 127 处带 before-image,其余只能看到 agent 自述

自己复现:

midflight replay ~/.claude/projects/-Users-zhangfengrui/<session>.jsonl --out replay.html
open replay.html

docs/demo/ 由 node scripts/record-demo.mjs <report.html> --out docs/demo 重新生成。


别信我说的,点开看

仓库里提交了三个真实产物。点开即看 —— 不用装、不用下载、不用注册账号。 每一个都是零外部依赖的单文件。

| | 你会看到 | 打开 | |---|---|---| | 交互回放 —— 一条 Codex 会话 | 拖时间轴、点任意一步、读 diff | 打开 · 33 KB | | 交互回放 —— 一条 Claude Code 会话 | 带压缩锯齿事件的那条 | 打开 · 56 KB | | PR 摘要块 —— GitHub 安全 | 你真正贴进 review 评论的那一份 | 打开 · 1 KB |

第三个才是这个项目的重点。GitHub 会剥掉 <script> 和 <style>,所有 HTML 导出器都会在 PR 评论里死掉;那一份只用 details / summary / table / pre / code / div 生成,贴进去还能原样存活。它只有 1 KB —— 所以有人会读。

问题在哪

这是本机一条真实会话,用 midflight doctor 量出来的,没有四舍五入、没有示意图:

| | | |---|---| | 日志体积 | 109 MiB | | 步数 | 14,905 | | 工具调用 | 3,689 | | 其中改动文件 | 1,720 次 —— 全部由 shell 命令承载 | | 记录了改前内容的 | 0 次 | | 上下文压缩 | 22 次 |

也就是说:日志知道这 1,720 个文件被改过、也知道是哪条命令改的,却不知道任何一个文件 改之前长什么样。上下文被压缩了 22 次,日志记下了"发生过",但没记下"什么活了下来"。

从这次会话里产出的代码,现在只剩一个 diff。而产生这个 diff 的 109 MiB 推理过程, 没有哪个 PR 评审人会去打开。于是他们像陌生人一样读 diff,评论一句"这个怎么测",翻篇。 想解释?重跑一次 agent —— 得到的是一个新会话,和当初写出代码的那条已经不是同一条。

midflight 回放的是真正写出那份代码的那条会话。 不是摘要,不是报告 —— 是一条可以来回拖动的时间轴,带真实的 diff、真实的上下文用量,以及一句诚实的 话:这个会话到底有多少比例能重建。

一条命令:

npx midflight-replay replay ~/.codex/sessions/2026/09/27/rollout-....jsonl --out replay.html

replay.html 是单个自包含文件。不用起服务、不用 CDN、不用构建、不发任何网络请求 —— 从 file:// 打开能用,贴成 PR 附件能用,断网笔记本能用,2030 年还能用。

零依赖、零构建、零网络请求、零遥测。


安装

需要 Node 20+,别的都不要。

npx midflight-replay replay <session.jsonl> --out replay.html

或者装到全局 —— 注意二进制命令叫 midflight,就像 @angular/cli 装出来的是 ng:

npm i -g midflight-replay
midflight doctor <session.jsonl>

工具本身不需要 npm install —— 运行时依赖是 0 个。仓库里的 devDependencies 只用于 编译和测试源码。


六十秒,从 clone 到能看的回放

git clone https://github.com/kevindurant735rocket-creator/midflight-replay.git
cd midflight-replay && npm install && bash scripts/demo-60s.sh --self

这就是整个 demo。它会自动找到你机器上最大的真实会话日志(~/.codex 或 ~/.claude), 回放它,然后把它干了什么打印出来:

  input        110 MiB of raw JSONL
  output       3.4M, one file, no sibling assets
  wall clock   454 ms
 { "kept": 4016, "total": 14905, "coverage": "diff-only", "parseMs": 387 }

done in 53 ms — open it:
  open demo-60s.html

这些数字是在跑它的机器上实测的,不是从 benchmark 抄的。去掉 --self 就用内置 fixture 跑 53 ms 那条路径,不需要任何会话日志。


支持哪些智能体

midflight agents 扫的是你本机的日志目录,每跑一次都是实测:

$ midflight agents --probe
agent                 status       sessions   size        newest
--------------------  -----------  ---------  ----------  -----------------
Codex CLI             readable     833        628.0 MB    2026-09-28
Claude Code           readable     173        226.9 MB    2026-09-27
Cursor                no adapter   1          8.6 KB      2026-08-31
...
2 of 3 installed agents readable; 8 not installed on this machine.
  ✓ Codex CLI: newest log: 2269 steps, 0 parse errors
  ! Cursor: no adapter — Cursor keeps chat state in a private store, not a JSONL transcript (1 file(s) found)

--probe 会真去解析每个可读智能体最新的那份日志,所以"readable"的意思是 "这份文件刚刚解析通过了",不是"应该能行"。装了但读不了的智能体不会被藏起来,而是 连真实文件数一起列出来。注册表覆盖 11 个宿主,目前 Codex 和 Claude Code 是完整 adapter,其余每一行都写清了为什么还不支持。

装进你自己的智能体

midflight install codex        # 只写一个文件:~/.codex/skills/midflight-replay/SKILL.md
midflight install --all        # 所有已知宿主
midflight install --dry-run    # 只打印路径,不写盘

只写一个 SKILL.md,别的什么都不碰 —— 没有 hook、没有常驻进程、不改配置、不联网。 这是故意的:midflight 读的是智能体自己已经写下的日志,没有东西需要拦截;而给一个 长会话套一层壳子,只会多一个能把会话搞崩的东西。这个 skill 是纯 Markdown,装之前 你能自己读完;不带 --force 时它拒绝覆盖已存在的不同文件;skill 里写的每条命令 都有测试断言在同一个构建里真的存在。

| 宿主 | 路径 | 文件 | |---|---|---| | Codex CLI | ~/.codex/skills/midflight-replay/ | SKILL.md | | Claude Code | ~/.claude/skills/midflight-replay/ | SKILL.md | | opencode | ~/.config/opencode/skill/midflight-replay/ | SKILL.md | | Gemini CLI | ~/.gemini/skills/midflight-replay/ | SKILL.md | | Cursor | ~/.cursor/rules/midflight-replay/ | *.mdc | | Windsurf | ~/.codeium/windsurf/rules/midflight-replay/ | *.md | | GitHub Copilot | ~/.github/prompts/midflight-replay/ | *.prompt.md |

各宿主的 frontmatter 是按各自的加载规则生成的(Codex/Claude Code/opencode/Gemini 要 name+description,Cursor 只要 description,Copilot prompt 不要),这条映射 有测试锁死,不是把 README 换个文件名。


我的会话日志在哪

midflight 读的是 agent 本来就在写的 JSONL。它不要求你打开任何开关,也不碰你的工作区。

| Agent | 默认位置 | 文件 | |---|---|---| | Codex CLI | ~/.codex/sessions/YYYY/MM/DD/ | rollout-*.jsonl | | Claude Code | ~/.claude/projects/<转义后的工作目录>/ | <session-uuid>.jsonl |

# 最新的 Codex 会话
npx midflight-replay replay "$(ls -t ~/.codex/sessions/*/*/*/*.jsonl | head -1)" --out replay.html

# 最新的 Claude Code 会话
npx midflight-replay replay "$(ls -t ~/.claude/projects/*/*.jsonl | head -1)" --out replay.html

格式靠第一条完整记录结构上识别,不看文件名、不看目录名。两种都不认的话, 会带行号报错退出。


两种输出

GitHub 会把粘进评论里的 <script> 和 <style> 全部剥掉。所有 HTML 导出器都死在这。 所以 midflight 有两种形态,你选:

1. --out replay.html —— 交互件

完整体验,单文件全内联。

  • 主轴 —— 会话时间轴,每步一根条,按类型着色
  • 副轴 —— 堆叠的上下文构成(消息 / 推理 / 工具调用 / 工具输出)。点色块或图例, 直接跳到第一个含该类别的步
  • 播放器 —— 可拖动;空格 播放/暂停,←/→ 或 j/k 单步, PageUp/PageDown 跳 20 步,Home/End 首尾。也可直接点
  • 单步详情 —— payload、token 用量;编辑步给带行号的 unified diff
  • 压缩标记 —— 上下文在哪里被 compact,画在轴上
  • 诚实覆盖条 —— 见下

实测(真实数据):109 MiB 会话里保留 14,905 步中的 4,016 步,输出 3.38MB, 每步 scrub 延迟 <100ms。

2. --paste —— GitHub 安全块

npx midflight-replay replay session.jsonl --paste > digest.html

≤60KB,只含 details / summary / table / pre / code / div。零 <script>、 零 <style>、零 on*= 内联事件、零外部引用 —— 这些由测试机检断言,不是口头承诺。 它按设计就是无 CSS 的:即使宿主把所有 style 属性剥光,仍然可读。

它是一份事后解剖摘要,不假装自己是可交互回放。放不下的时候按优先级倒序丢段, 并且明说丢了多少。


放到 PR 上

大部分审阅者不会去找一个 CLI。action 把摘要放到他们本来就在的地方。

# .github/workflows/agent-audit.yml
name: agent audit
on: pull_request
permissions:
  contents: read
  pull-requests: write
jobs:
  replay:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: kevindurant735rocket-creator/[email protected]
        with:
          session: auto              # .agent-sessions/ 下最新的 .jsonl
          # session: logs/last-run.jsonl

它读仓库里已提交的会话日志,生成可直接粘贴的摘要,在 PR 上留 一条 评论 —— 原地更新、不堆叠,所以 40 个 commit 的 PR 不会攒出 40 份一模一样的摘要。 完整的可交互回放仍然由你自己手动附上;action 只发读得懂的那一半。

它做不到什么: CI runner 从来没跑过 Codex 或 Claude Code,所以除非你把日志 提交进仓库,否则它没有会话可读。把 session: 指向仓库里的文件,或者用 dir: 指到你自己的日志目录。

它花多少: 一次 npm ci 加一次 tsc,项目零运行时依赖。本机真实的 109 MiB(114,325,714 字节)/ 30,736 行 / 14,905 步 Codex 会话解析耗时 < 500ms,产出 9,381 字节摘要。

"这段 yaml 就是全部配置:抄进你自己的 .github/workflows/,它就会在你的 PR 上跑。

本仓库把同样这两个文件跑在自己的 push 和 PR 上,顶部那枚徽章就是上一次真实运行的状态,不是说法。 检查清单只写一遍,在 scripts/ci-checks.sh 里:.githooks/pre-push 跑它,CI 也跑它, 所以本地推上去是绿的、CI 是绿的,意思是同一件事。


诚实的覆盖度

这是整个项目最重要的一个设计决定。

会话日志不一定包含足够信息来重建磁盘上发生的事。Codex 只写 cmd 和 path 参数 —— 在实测的那条会话里,3,689 次 tool_call、30,736 行日志中,old_string / patch 出现次数为零。 Claude Code 的 Edit 带 old_string + new_string,Write 带完整 content。

所以诚实的答案因 agent 而异。midflight 把它印出来,而不是给你看一个空 diff 却什么都不说:

| 判定 | 含义 | |---|---| | full 全部可撤回 | 每个编辑步都有 before-image,会话可重建 | | partial 部分可撤回 | 部分编辑步有 before-image,覆盖条显示比例 | | diff-only 仅 diff | 日志记了"写过这个文件",但没记之前的内容 | | no-edits 无编辑 | 这条会话根本没改文件 |

实测数据,不是推测:

| 会话 | 大小 | 解析 | 输出 | 步数 | 覆盖判定 | |---|---|---|---|---|---| | Codex rollout | 109 MiB | ~0.4 s | 3.38 MiB | 4,016 / 14,905 | diff-only —— 1,720 处 shell 改动,0 处 before-image | | Claude Code | 31 MiB | ~0.13 s | 2.19 MiB | 3,000 / 3,111 | partial —— 244 次编辑,127 次带 before-image |

第二条诚实规则:适配器无法分类的步会被标注、计数并渲染,绝不静默丢弃。Claude Code 会写入 会话元数据记录(file-history-snapshot / ai-title / permission-mode 等),它们不承载 agent 动作 —— 所以 midflight 现在认得出它们,而不是丢进一个桶里:ai-title 与 agent-name 直接变成会话标题,file-history-delta 归为 chrome,compact_boundary 变成一等的压缩事件。最后这条以前是个沉默的谎报:上面那条 32MB 会话里有 10 个 compact_boundary,早期版本把它们当 chrome 吞掉,于是报告写「未观测到压缩事件」。

现在那条会话的 unknownCount: 0,全部 3,111 步分布是:1,040 工具调用、1,040 工具输出、 424 assistant、415 reasoning、121 user、61 note、10 次压缩。故意不读的部分写在 docs/KNOWN-GAPS.md —— 包括为什么不解码 ~/.claude/file-history, 以及证明这件事的命令。接下来做什么、明确不做什么,排序在 docs/BACKLOG.md。

两行都可以自己复现:

npx midflight-replay doctor <session.jsonl> --json   # steps / byKind / parseErrors / unknownSteps
/usr/bin/time -l npx midflight-replay replay <session.jsonl> --out /tmp/r.html --json  # RSS

那个 109 MiB 的文件峰值 RSS 273MB(286,736,384 字节)。解析是逐行流式的,从不整文件读进内存。


隐私

midflight 不写你的工作区、不读你的 git 历史、不发任何网络请求。 一次都没有, 任何代码路径都没有。生成的报告有浏览器验收断言:零外部请求。

脱敏默认开启,在任何东西进入报告之前就跑完:

  • OpenAI / Anthropic key、GitHub PAT、Slack token、AWS key、Google API key
  • PEM 私钥块、Bearer 头、JWT
  • api_key / secret / password / token = ... 赋值
  • 邮箱地址
  • 你的家目录 → /HOME,/Users/<你> → /Users/USER

如果你是故意在调试某个密钥,用 --no-redact 关掉。没有任何东西被上传,所以 "被上传"不构成失败模式。报告里只显示哪条规则命中了几次,永远不显示值。


命令

midflight replay <session.jsonl> [options]   生成自包含回放
midflight doctor <session.jsonl> [--json]    解析并体检;输入有问题时 exit 1
midflight stats  <session.jsonl> [--json]    解析并打印步数统计
midflight postmortem <session.jsonl> [--json] 数循环、反复改同一处、上下文压力
midflight revert  <report.html> --step <n>    打印撤销第 n 步所需的补丁
midflight revert  <report.html> --list       列出哪些步骤可以撤回
midflight agents [--json] [--probe]         本机装了哪些智能体、哪些读得了
midflight install <agent>|--all [--dry-run]  把 midflight skill 装进那个智能体
midflight redact                            对 stdin 跑脱敏
midflight --version                          打印已安装的版本

| 选项 | 默认 | 含义 | |---|---|---| | --out <file> | stdout | HTML 写到这里 | | --paste | 关 | 改输出 GitHub 安全块 | | --max-steps <n> | 3000 | 工具调用和压缩事件永不丢弃 | | --per-step-chars <n> | 1200 | 每步 payload 上限 | | --no-redact | 关 | 关脱敏 | | --json | 关 | 机器可读摘要走 stderr |

文件可疑的时候跑 doctor。它会报出第一条坏记录的行号,并以非零码退出。 可以放进 CI。

revert —— 报告的逆运算

报告能证明 agent 做了什么。revert 把其中一步变回一个补丁:

midflight revert report.html --list                  # 哪些步可以撤
midflight revert report.html --step 2 --out p.diff   # 把那一步写成补丁
git apply --check -R p.diff                           # 先验
git apply -R p.diff                                   # 看完再撤

它绝不写你的工作区 —— 唯一会写的是 git apply,由你亲自下,你已经先看过补丁。 --list 只需要报告本身,所以同事没你的 checkout 也能看出哪些步可撤。

某一步如果没有可恢复的 before-image,revert 会非零退出并明确拒绝, 而不是吐一个空补丁。悄悄给一个空操作贴上"已撤销"的标签,比直接说不行更糟。


为什么不是另外八个工具

现在已经有八个项目在做"agent 会话回放"(实测星标:388 / 372 / 268 / 110 / 76 / 14 / 13 / 3)。把八个都看过一遍之后,三条结论:

  1. 会话回放是功能,不是品类。 Sentry 和 PostHog 都把它当更大产品里的一个功能。 底层原语 rrweb 有 2 万星。独立 viewer 是在抢边角料。
  2. "本地优先飞行记录仪"这个说法已经有人占了。 有一个项目自己的描述和这句话 几乎逐字重合 —— 76 星、四种语言、31,000 字符的 README、MIT 许可, 停更两个月,开源 issue 数为零。这不是产品失败,是分发失败。
  3. 八个全是"你自己一个人用"的工具。 没有一个的产物是为"发出去"设计的。

midflight 押的是第三条。产物是一个发给不在场的人的文件。场景是评审 AI 生成的 PR —— 此刻正在大规模发生 —— 而且这个场景自带一个裂变位,那八个都没有:PR 评论。

逐仓库的实测数据和可复跑的取证命令:docs/COMPETITIVE.md。


如果你是在 npm 上搜"agent replay"搜到这儿的

你搜到两个包。下面的数字是当场实测的,取证命令在 docs/COMPETITIVE.md:

| | agent-replay | flightrec | midflight-replay | |---|---|---|---| | npm 版本 | 0.1.1 | 0.9.0 | 0.1.0 | | 最后发布 | 2026-02-16 | 2026-07-15 | 今天 | | 月下载 | 9 | 16 | — | | GitHub 仓库 | 404,已删或转私有 | 0★,建仓和最后 push 同一天 | 公开,CI 全绿 | | 它是什么 | "DevTools for replaying AI agent sessions" | "A flight recorder for Codex sessions" | 一个贴到 PR 上的文件 | | 源码 | 未公开 | 未公开 | 完整开源,MIT |

关键差别不是功能。是那两个包装上也验证不了:一个仓库根本访问不到,另一个 仓库从建仓起就没过第二个提交。你读不了源码,提不了 issue,也没法确认它现在还能不能跑。

所以这里的验收标准刻意选成最便宜、也最没法作假的那条:装上它,做出一个东西。

npx midflight-replay replay "$HOME"/.claude/projects/*/*.jsonl --out replay.html

这条命令要是能产出一个你直接发给"问你这个问题的人"的文件,比较就结束了。 上面那台机器上,110 MiB 的 JSONL 在 0.46 秒内变成 3.4 MiB 的单文件 HTML, 全程不碰网络。


路线图

刻意做小。已发货 9 项,没有第 11 项排在后面充数。

  • [x] Codex + Claude Code 适配器,自动识别
  • [x] 双轴时间轴 + 可点击的上下文构成
  • [x] 编辑步的 unified diff,带行号
  • [x] 双输出:交互 HTML + GitHub 安全块
  • [x] 每份报告都带诚实覆盖判定
  • [x] 默认脱敏、零网络
  • [x] doctor 行级失败定位
  • [x] revert —— 从报告里撤一步,可 git apply -R
  • [x] postmortem —— 循环、反复改同一处、上下文压力,全部从日志数出来 (同一块面板也进了 HTML 报告:每条发现一行,点一下就跳到起头那一步)
  • [ ] 更多适配器,等真实日志里出现再加 —— 不预先排任何一家

刻意不做:服务端、账号、数据库、托管看板、重跑/分叉。每一个都需要一次网络调用, 而"不发网络请求"正是这个项目存在的理由。


开发

npm install          # 只有 devDeps:typescript、vitest、playwright
npm run build        # tsc -> dist/
npm test             # 39 个单测
node scripts/browser-check.mjs out.html out2.html   # 两条 fixture 上 62 条浏览器断言;条数随输入变

浏览器验收是单独一条命令,这是故意的:它要下载 Chromium,CI 不该每次提交都付这个成本。

两种 agent 格式的内部结构见 docs/FORMATS.md。

贡献

见 CONTRIBUTING.md。一句话版本:零依赖和零网络不是偏好,是产品本身 —— 加了运行时依赖的 PR 不会合。

许可

MIT