difftab 0.4.1 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,84 +3,139 @@
3
3
  difftab
4
4
  </h1>
5
5
 
6
+ <p align="center"><strong>See what your AI coding agent changed — in one browser tab.</strong></p>
7
+
6
8
  <p align="center">
7
9
  <a href="https://www.npmjs.com/package/difftab"><img src="https://img.shields.io/npm/v/difftab" alt="npm"></a>
8
10
  <a href="https://nodejs.org"><img src="https://img.shields.io/node/v/difftab" alt="node"></a>
9
- <a href="#never-writes-to-your-repository"><img src="https://img.shields.io/badge/dependencies-0-brightgreen" alt="dependencies"></a>
11
+ <a href="#security"><img src="https://img.shields.io/badge/dependencies-0-brightgreen" alt="dependencies"></a>
10
12
  <a href="LICENSE"><img src="https://img.shields.io/npm/l/difftab" alt="license"></a>
11
13
  </p>
12
14
 
13
- **See what your AI coding agent changed — in one tab.**
15
+ <p align="center">
16
+ <a href="#installation">Install</a> ·
17
+ <a href="#usage">Usage</a> ·
18
+ <a href="#why-difftab">Why</a> ·
19
+ <a href="#faq">FAQ</a> ·
20
+ <a href="README.zh-CN.md">中文文档</a>
21
+ </p>
22
+
23
+ A read-only, zero-dependency local viewer for your git working tree: the diff, the file
24
+ tree and the branch status, refreshing itself while the agent keeps writing. Close the tab
25
+ and it exits.
26
+
27
+ ## Why difftab
28
+
29
+ You run Claude Code, Codex, OpenCode or another agent from a terminal. It finishes a task,
30
+ and you want to see what it actually did. The agent's own diff scrolls past in the
31
+ terminal, which is not the place to read a 300-line patch — so you open VS Code, or
32
+ whatever IDE you keep around for this, not to edit anything, just to read the diff, glance
33
+ at the tree, check the branch, and close it again.
14
34
 
15
- Run one command in your repo. A local page opens with your working-tree diff and branch
16
- status — what `git status` and `git diff HEAD` would show — read-only, refreshing itself
17
- while the agent keeps writing. Close the tab and the process exits.
35
+ difftab is that half of the editor without the editor. One command, one tab, and only the
36
+ three things you actually looked at. It only reads git, so it works with any agent, any
37
+ language and any repository. And if an agent now writes all your code, you can uninstall
38
+ the IDE.
18
39
 
19
- [中文文档](README.zh-CN.md)
40
+ ## Features
20
41
 
21
- ## Quick start
42
+ - **The diff, the way an editor shows it** — staged, unstaged, untracked and conflicting
43
+ changes, side by side with syntax highlighting.
44
+ - **The whole repository, not only what changed** — browse the file tree and open any file.
45
+ - **Branch status you can trust** — ahead/behind, no upstream, detached HEAD, a rebase or
46
+ merge still in progress.
47
+ - **Live while the agent writes** — the tab refreshes on its own as files change.
48
+ - **Never writes to your repository** — read-only git only, enforced by CI gates rather
49
+ than by promise. Details under [Security](#security).
50
+ - **Nothing to keep running** — starts instantly, zero dependencies, exits when you close
51
+ the tab.
52
+
53
+ ## Installation
54
+
55
+ Requires **Node.js 22 or newer** on macOS, Windows or Linux. No other dependencies.
56
+
57
+ ```bash
58
+ npm i -g difftab
59
+ ```
60
+
61
+ Or try it without installing:
22
62
 
23
63
  ```bash
24
- cd /path/to/your/repo
25
64
  npx difftab
26
65
  ```
27
66
 
28
- Or install it once — `npm i -g difftab` — and just run `difftab`.
67
+ ## Usage
68
+
69
+ Run it inside any git repository:
70
+
71
+ ```bash
72
+ cd /path/to/your/repo
73
+ difftab
74
+ ```
75
+
76
+ A browser tab opens with the current diff. Keep it open next to the agent: the tab
77
+ refreshes as files change, and when you close it the process exits on its own. Running
78
+ `difftab` again in the same repository reuses the running instance instead of starting a
79
+ second one.
80
+
81
+ | Option | What it does |
82
+ |---|---|
83
+ | `--no-open` | Print the URL instead of opening a browser |
84
+ | `-v`, `--version` | Print the version and exit |
85
+ | `-h`, `--help` | Print help and exit |
86
+
87
+ There is nothing to configure: no port to pick, no config file.
88
+
89
+ ## How it works
29
90
 
30
- Requires **Node.js 22 or newer** on macOS, Windows or Linux. Zero dependencies.
91
+ `difftab` runs the same read-only git commands `git status` and `git diff HEAD` would, and
92
+ serves the result from a local server on `127.0.0.1`. The page loads a patch when you click
93
+ it and refreshes as files change; 45 seconds after the last tab closes, the process exits.
31
94
 
32
- - `--no-open` — print the URL instead of opening a browser
33
- - `-v`, `--version` — print the version and exit
34
- - `-h`, `--help` — print help and exit
95
+ ## Security
35
96
 
36
- Running it again in the same repository reuses the running instance.
97
+ Read-only, local-only, nothing to trust but your own machine.
37
98
 
38
- ## What you get
99
+ **It never writes to your repository.** difftab only ever runs read-only git commands — no
100
+ stage, commit, discard, pull, push, branch or stash. Two gates enforce this on every
101
+ change: a `GIT_TRACE` allowlist over every git invocation, and a byte-for-byte comparison
102
+ of `.git` before and after. `dist/server/main.js` ships unminified, so you can audit it by
103
+ hand.
39
104
 
40
- - **Change list** — staged, unstaged, untracked and conflicting files in four groups, with
41
- untracked directories expanded to files.
42
- - **Diffs, lazily** — click a file to load its patch, rendered by
43
- [diff2html](https://diff2html.xyz/) + highlight.js in a VS Code-like theme, side by side
44
- until the pane gets too narrow.
45
- - **File tree** — a second sidebar tab browses the whole repository rather than only what
46
- changed: tracked, untracked and ignored files (the ignored ones dimmed), loaded one
47
- directory at a time. Click any file to read it, highlighted by the same theme.
48
- - **Branch status** — branch name, ahead/behind counts, "no upstream", detached HEAD, and
49
- an in-progress rebase / merge / cherry-pick / revert / bisect / `git am`.
50
- - **Auto-refresh** — a file watcher pushes changes over SSE, falling back to polling where
51
- recursive watching would exhaust the inotify quota (and saying so in the UI).
52
- - **Exits on its own** — 45 seconds after the last tab closes.
53
- - **Cheap to run** — about 40 ms from launch to a listening server, well inside the 300 ms
54
- budget CI enforces on every commit across nine Node × OS combinations; the JS bundle is
55
- 75 KB gzipped.
105
+ **Nothing leaves your machine.** The server binds `127.0.0.1`; the only HTTP request
106
+ difftab makes is to localhost, to see whether an instance is already running for this
107
+ repository. No telemetry, no account, no cloud.
56
108
 
57
- Empty repositories, interrupted rebases, linked worktrees, submodules, binary and >5 MB
58
- files, renames, and paths with spaces, quotes, CJK or emoji are handled explicitly.
109
+ **The local page is locked down.** Each session gets a random token, handed to the browser
110
+ once through the URL and then kept in an `HttpOnly; SameSite=Strict` cookie while the URL
111
+ is redirected clean. Every request is checked against the `Host` header — the actual
112
+ defense against DNS rebinding, rather than the token alone — and against `Origin`, and the
113
+ page runs under a `default-src 'none'` CSP that also blocks framing, `<base>` rewriting and
114
+ form submission. There is no development escape hatch: no environment variable relaxes any
115
+ of those checks.
59
116
 
60
- difftab is deliberately a viewer: no editing, history, blame or review workflow
61
- ([out-of-scope list](CONTRIBUTING.md#the-read-only-promise-is-not-negotiable)).
117
+ ## FAQ
62
118
 
63
- ## Never writes to your repository
119
+ **Does it work with my agent?** — Yes. difftab never talks to the agent — it only reads
120
+ git — so anything that writes files into a git working tree looks the same to it: Claude
121
+ Code, Codex, OpenCode, Aider, a human with vim.
64
122
 
65
- Not a best-effort claim: difftab only ever runs read-only git commands — no stage, commit,
66
- discard, pull, push, branch or stash. Two gates enforce it on every change: a `GIT_TRACE`
67
- allowlist over every git invocation, and a byte-for-byte comparison of `.git` before and
68
- after. And `dist/server/main.js` ships unminified, so you can audit it by hand.
123
+ **Can I stage, commit or discard from it?** — No, and it never will be. Read-only is the
124
+ product's core promise, not a missing feature; see [Non-goals](#non-goals).
69
125
 
70
- ## Nothing leaves your machine
126
+ **The UI says "Polling" — is something wrong?** — No. It means difftab could not use native
127
+ file watching here: Node older than 24.14 on Linux, a repository on a network drive or a
128
+ Docker volume, or an exhausted inotify quota. It runs `git status` every 1.5 seconds
129
+ instead, so everything still refreshes; it may just land a second or two later.
71
130
 
72
- The server binds `127.0.0.1` on a port the kernel picks, and the only HTTP request difftab
73
- makes is to localhost, to see whether an instance is already running for this repository.
74
- No telemetry, no account, no cloud.
131
+ ## Non-goals
75
132
 
76
- Each session gets a random token, handed to the browser once through the URL and then kept
77
- in an `HttpOnly; SameSite=Strict` cookie while the URL is redirected clean. Every request
78
- is checked against the `Host` header — the actual defense against DNS rebinding, rather
79
- than the token alone — and against `Origin`, and the page runs under a `default-src 'none'`
80
- CSP that also blocks framing, `<base>` rewriting and form submission. There is no
81
- development escape hatch: no environment variable relaxes any of those checks.
133
+ difftab is deliberately a viewer. Permanently out of scope: any repository write operation,
134
+ code editing, accounts and cloud sync, and multi-user review workflows. Out of the current
135
+ version: commit history, branch lists, blame. The full list, and the reasoning, is in
136
+ [CONTRIBUTING.md](CONTRIBUTING.md#the-read-only-promise-is-not-negotiable).
82
137
 
83
- ## Development
138
+ ## Contributing
84
139
 
85
140
  ```bash
86
141
  pnpm install --frozen-lockfile
package/README.zh-CN.md CHANGED
@@ -3,62 +3,100 @@
3
3
  difftab
4
4
  </h1>
5
5
 
6
+ <p align="center"><strong>一个浏览器标签页,看懂 AI 编码 Agent 改了哪些代码。</strong></p>
7
+
6
8
  <p align="center">
7
9
  <a href="https://www.npmjs.com/package/difftab"><img src="https://img.shields.io/npm/v/difftab" alt="npm"></a>
8
10
  <a href="https://nodejs.org"><img src="https://img.shields.io/node/v/difftab" alt="node"></a>
9
- <a href="#全程零写操作"><img src="https://img.shields.io/badge/dependencies-0-brightgreen" alt="dependencies"></a>
11
+ <a href="#安全"><img src="https://img.shields.io/badge/dependencies-0-brightgreen" alt="dependencies"></a>
10
12
  <a href="LICENSE"><img src="https://img.shields.io/npm/l/difftab" alt="license"></a>
11
13
  </p>
12
14
 
13
- **一个标签页,看懂 AI 编码 Agent 改了哪些代码。**
15
+ <p align="center">
16
+ <a href="#安装">安装</a> ·
17
+ <a href="#用法">用法</a> ·
18
+ <a href="#为什么做-difftab">为什么</a> ·
19
+ <a href="#常见问题">常见问题</a> ·
20
+ <a href="README.md">English</a>
21
+ </p>
22
+
23
+ 一个只读、零依赖的本地工作区查看器:diff、文件树、分支状态,在 agent 继续写的过程中自动刷新。关掉标签页,它就退出。
24
+
25
+ ## 为什么做 difftab
26
+
27
+ 你在终端里跑 Claude Code、Codex、OpenCode 之类的 agent。它做完一件事,你想看看它到底改了什么。agent 自带的 diff 在终端里刷过去,那不是读一份三百行补丁的地方——于是你打开 VS Code,或者手边为此留着的随便哪个 IDE,什么都不编辑,只是看看 diff、瞄一眼目录树、确认下分支,然后关掉。
14
28
 
15
- 在仓库目录敲一条命令,本地网页随即打开,只读展示当前工作区的 diff 与分支状态(就是 `git status` 与 `git diff HEAD` 的内容),并在 agent 继续写的过程中自动刷新;关掉标签页,进程自行退出。
29
+ difftab 就是编辑器里的这一半,去掉编辑器。一条命令、一个标签页,只装你真正会看的那三样。它只读 git,所以配哪个 agent、哪种语言、哪个仓库都一样。如果现在代码全由 agent 来写,IDE 就可以卸了。
16
30
 
17
- [English](README.md)
31
+ ## 特性
18
32
 
19
- ## 快速开始
33
+ - **像编辑器那样看 diff**——已暂存、未暂存、未跟踪、冲突一目了然,并排展示,带语法高亮。
34
+ - **整个仓库,而不只是改动过的那些**——浏览文件树,点开任一文件即可查看。
35
+ - **信得过的分支状态**——ahead/behind、无上游、游离 HEAD、进行到一半的 rebase 或 merge。
36
+ - **agent 边写边看**——文件一变,标签页自己刷新。
37
+ - **绝不写你的仓库**——只发只读的 git 命令,由 CI 门禁保证,不是靠承诺。细节见[安全](#安全)。
38
+ - **不用养着**——瞬间启动,零依赖,关掉标签页就退出。
39
+
40
+ ## 安装
41
+
42
+ 要求 **Node.js 22 或更高**,macOS / Windows / Linux 三端均支持,没有其他依赖。
43
+
44
+ ```bash
45
+ npm i -g difftab
46
+ ```
47
+
48
+ 也可以不装直接试:
20
49
 
21
50
  ```bash
22
- cd /path/to/your/repo
23
51
  npx difftab
24
52
  ```
25
53
 
26
- 也可以装一次——`npm i -g difftab`——之后直接敲 `difftab`。
54
+ ## 用法
55
+
56
+ 在任意 git 仓库目录下执行:
57
+
58
+ ```bash
59
+ cd /path/to/your/repo
60
+ difftab
61
+ ```
62
+
63
+ 浏览器标签页随即打开,展示当前的 diff。让它在 agent 旁边开着:文件一变标签页就刷新,关掉它进程自己退出。在同一个仓库里再敲一次 `difftab`,会复用已在跑的实例,不会起第二个。
64
+
65
+ | 选项 | 作用 |
66
+ |---|---|
67
+ | `--no-open` | 只打印 URL,不拉起浏览器 |
68
+ | `-v`, `--version` | 打印版本号并退出 |
69
+ | `-h`, `--help` | 打印帮助并退出 |
70
+
71
+ 没有任何东西需要配置:不用选端口,没有配置文件。
72
+
73
+ ## 工作原理
27
74
 
28
- 要求 **Node.js 22 或更高**,macOS / Windows / Linux 三端均支持,零依赖。
75
+ `difftab` 只运行 `git status` 与 `git diff HEAD` 那一类只读 git 命令,由一个只绑 `127.0.0.1` 的本地服务把结果交给页面。页面点到哪个补丁才加载哪个,文件一变就刷新;最后一个标签页关掉 45 秒后进程自行退出。
29
76
 
30
- - `--no-open`——只打印 URL,不拉起浏览器
31
- - `-v`, `--version`——打印版本号并退出
32
- - `-h`, `--help`——打印帮助并退出
77
+ ## 安全
33
78
 
34
- 在同一个仓库里再敲一次,会复用已在跑的实例。
79
+ 只读、只在本机,除了你自己的电脑不需要信任任何东西。
35
80
 
36
- ## 能看到什么
81
+ **全程零写操作。** difftab 只发只读的 git 命令——不 stage、不 commit、不 discard、不 pull / push、不建分支、不 stash。两道门禁在每次改动上守着:一道是覆盖每一次 git 调用的 `GIT_TRACE` 命令白名单,另一道是 `.git` 前后逐字节比对。`dist/server/main.js` 不压缩不混淆发布,可以手工审计。
37
82
 
38
- - **变更列表**——已暂存、未暂存、未跟踪、冲突四组,未跟踪的目录展开到文件粒度。
39
- - **按文件懒加载的 diff**——点开某个文件才取它的补丁,渲染用 [diff2html](https://diff2html.xyz/) + highlight.js,配色仿 VS Code,面板窄到放不下两列时自动切成逐行。
40
- - **文件树**——侧栏第二个 tab 浏览整个仓库,而不只是改动过的那些:已跟踪、未跟踪与被忽略的文件(后者灰显),按目录懒加载。点任一文件在右侧只读查看,高亮复用同一套配色。
41
- - **分支状态**——当前分支、ahead/behind 计数、无上游、游离 HEAD,以及进行中的 rebase /
42
- merge / cherry-pick / revert / bisect / `git am`。
43
- - **自动刷新**——文件监听经 SSE 推到前端;递归监听会耗尽 inotify 配额的场合改用轮询,并在界面上标注。
44
- - **自己退出**——最后一个标签页关掉 45 秒后自动退。
45
- - **跑起来很轻**——从启动到端口就绪约 40ms,远在 CI 每次提交都验的 300ms 预算之内(九个 Node × 平台组合各跑一遍);打包后的 JS gzip 75KB。
83
+ **全程不外传。** 服务只绑 `127.0.0.1`;difftab 发出的唯一一个 HTTP 请求是打到 localhost 上的,用来确认这个仓库是不是已经有实例在跑。无遥测、无账号、无云端。
46
84
 
47
- 空仓库、停在中途的 rebase、linked worktree、submodule、二进制与超过 5MB 的文件、重命名,以及带空格、引号、中日韩文字或 emoji 的路径,都是被显式处理的。
85
+ **本地页面也是锁死的。** 每次会话生成一个随机 token,先经 URL 交给浏览器,随后落进 `HttpOnly; SameSite=Strict` 的 cookie,并把 URL 上的 query 重定向掉。每个请求都校验 `Host` 头与 `Origin`——`Host` 那道才是 DNS rebinding 的正面防御,光靠 token 挡不住;页面跑在 `default-src 'none'` 的 CSP 之下,被嵌 iframe、`<base>` 改写相对 URL 与表单外发也一并挡掉。后端没有任何开发用的后门:不存在放宽这几道校验的环境变量。
48
86
 
49
- difftab 刻意只是个查看器:不编辑、不看历史、不做 blame、不承载评审流程(完整的不做清单见 [CONTRIBUTING.md](CONTRIBUTING.md#the-read-only-promise-is-not-negotiable))。
87
+ ## 常见问题
50
88
 
51
- ## 全程零写操作
89
+ **能配我用的 agent 吗?**——能。difftab 从不与 agent 打交道,它只读 git,所以凡是往 git 工作区里写文件的东西在它眼里都一样:Claude Code、Codex、OpenCode、Aider、拿着 vim 的人。
52
90
 
53
- 不是「尽量」:difftab 只发只读的 git 命令——不 stage、不 commit、不 discard、不 pull / push、不建分支、不 stash。两道门禁在每次改动上守着:一道是覆盖每一次 git 调用的 `GIT_TRACE` 命令白名单,另一道是 `.git` 前后逐字节比对。后端也支持手工审计:`dist/server/main.js` 不压缩不混淆发布。
91
+ **能在里面 stage、commit 或 discard 吗?**——不能,将来也不会。只读是产品的核心承诺,不是还没做的功能;见[明确不做](#明确不做)。
54
92
 
55
- ## 全程不外传
93
+ **界面上写着「Polling」,是出问题了吗?**——没有。它表示 difftab 在这里用不了原生文件监听:Linux 上低于 24.14 的 Node、放在网络盘或 Docker 卷上的仓库、或 inotify 配额耗尽。于是改成每 1.5 秒跑一次 `git status`,一切照常刷新,只是可能晚一两秒。
56
94
 
57
- 服务只绑 `127.0.0.1`,端口由内核随机分配,而 difftab 发出的唯一一个 HTTP 请求是打到 localhost 上的,用来确认这个仓库是不是已经有实例在跑。无遥测、无账号、无云端。
95
+ ## 明确不做
58
96
 
59
- 每次会话生成一个随机 token,先经 URL 交给浏览器,随后落进 `HttpOnly; SameSite=Strict` 的 cookie,并把 URL 上的 query 重定向掉。每个请求都校验 `Host` 头与 `Origin`——`Host` 那道才是 DNS rebinding 的正面防御,光靠 token 挡不住;页面跑在 `default-src 'none'` 的 CSP 之下,被嵌 iframe、`<base>` 改写相对 URL 与表单外发也一并挡掉。后端没有任何开发用的后门:不存在放宽这几道校验的环境变量。
97
+ difftab 刻意只是个查看器。长期不做:任何仓库写操作、代码编辑、账号与云同步、多用户评审流程。当前版本不做:提交历史、分支列表、blame。完整清单与理由见 [CONTRIBUTING.md](CONTRIBUTING.md#the-read-only-promise-is-not-negotiable)。
60
98
 
61
- ## 开发
99
+ ## 参与开发
62
100
 
63
101
  ```bash
64
102
  pnpm install --frozen-lockfile