difftab 0.1.0 → 0.1.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 +35 -118
- package/README.zh-CN.md +22 -100
- package/dist/server/main.js +20 -1
- package/dist/web/app.css +1 -1
- package/dist/web/app.js +15 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,155 +1,72 @@
|
|
|
1
1
|
# difftab
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/difftab)
|
|
4
|
+
|
|
3
5
|
**See what your AI coding agent changed — in one tab.**
|
|
4
6
|
|
|
5
|
-
Run one command in your repo. A local page opens with your working-tree diff and
|
|
6
|
-
|
|
7
|
+
Run one command in your repo. A local page opens with your working-tree diff and branch
|
|
8
|
+
status — what `git status` and `git diff HEAD` would show — read-only, refreshing itself
|
|
9
|
+
while the agent keeps writing. Close the tab and the process exits.
|
|
7
10
|
|
|
8
11
|
[中文文档](README.zh-CN.md)
|
|
9
12
|
|
|
10
|
-
difftab is built for the moment right after an agent finishes (or while it is still
|
|
11
|
-
running): you want a quick look at the changes, not a review session. It shows the
|
|
12
|
-
same thing `git status` and `git diff HEAD` would, rendered as side-by-side diffs with
|
|
13
|
-
syntax highlighting, and it refreshes itself as the agent keeps writing. It never writes
|
|
14
|
-
to your repository — the core promise, enforced by two CI gates and
|
|
15
|
-
[described below](#never-writes-to-your-repository).
|
|
16
|
-
|
|
17
13
|
## Install
|
|
18
14
|
|
|
19
|
-
Nothing to install — run it in any repository:
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
npx difftab # pnpm users: pnpm dlx difftab
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
The first run spends a few seconds downloading and unpacking the package; later runs come
|
|
26
|
-
from the cache.
|
|
27
|
-
|
|
28
|
-
If you reach for it after every agent run, install it once instead — an `npx` run spends
|
|
29
|
-
more time resolving which version to fetch than difftab spends starting up:
|
|
30
|
-
|
|
31
15
|
```bash
|
|
32
|
-
|
|
16
|
+
npx difftab # or install it once: npm i -g difftab
|
|
33
17
|
```
|
|
34
18
|
|
|
35
|
-
Requires **Node.js 22
|
|
36
|
-
Node standard library, and the frontend is bundled at build time, so a global install
|
|
37
|
-
pulls in zero transitive packages.
|
|
19
|
+
Requires **Node.js 22 or newer** on macOS, Windows or Linux. Zero dependencies.
|
|
38
20
|
|
|
39
21
|
## Usage
|
|
40
22
|
|
|
41
23
|
```bash
|
|
42
24
|
cd /path/to/your/repo
|
|
43
|
-
difftab
|
|
25
|
+
difftab
|
|
44
26
|
```
|
|
45
27
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
| `-v`, `--version` | print the version and exit |
|
|
50
|
-
| `-h`, `--help` | print help and exit |
|
|
28
|
+
- `--no-open` — print the URL instead of opening a browser
|
|
29
|
+
- `-v`, `--version` — print the version and exit
|
|
30
|
+
- `-h`, `--help` — print help and exit
|
|
51
31
|
|
|
52
|
-
Running it again in the same repository reuses the running instance
|
|
53
|
-
second process.
|
|
32
|
+
Running it again in the same repository reuses the running instance.
|
|
54
33
|
|
|
55
34
|
## What you get
|
|
56
35
|
|
|
57
|
-
- **Change list** — staged, unstaged and
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
- **
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
-
|
|
72
|
-
reloads, sleep/wake and backgrounded tabs do not trigger it.
|
|
73
|
-
|
|
74
|
-
Edge cases are handled explicitly rather than left to fail: empty repositories (no
|
|
75
|
-
commits yet), detached HEAD, an interrupted rebase, linked worktrees, submodules, binary
|
|
76
|
-
files, files over 5 MB, renames (annotated with the old path and similarity), deleted
|
|
77
|
-
files, and paths containing spaces, quotes, CJK characters or emoji.
|
|
78
|
-
|
|
79
|
-
difftab is deliberately a viewer: no editing, no history, no blame, no review workflow.
|
|
80
|
-
The full out-of-scope list is in
|
|
81
|
-
[CONTRIBUTING.md](CONTRIBUTING.md#the-read-only-promise-is-not-negotiable) and
|
|
82
|
-
[`docs/spec.md`](docs/spec.md) §4.
|
|
36
|
+
- **Change list** — staged, unstaged, untracked and conflicting files in four groups, with
|
|
37
|
+
untracked directories expanded to files.
|
|
38
|
+
- **Diffs, lazily** — click a file to load its patch, rendered by
|
|
39
|
+
[diff2html](https://diff2html.xyz/) + highlight.js in a VS Code-like theme, side by side
|
|
40
|
+
until the pane gets too narrow.
|
|
41
|
+
- **Branch status** — branch name, ahead/behind counts, "no upstream", detached HEAD, and
|
|
42
|
+
an in-progress rebase / merge / cherry-pick / revert / bisect / `git am`.
|
|
43
|
+
- **Auto-refresh** — a file watcher pushes changes over SSE, falling back to polling where
|
|
44
|
+
recursive watching would exhaust the inotify quota (and saying so in the UI).
|
|
45
|
+
- **Exits on its own** — 45 seconds after the last tab closes.
|
|
46
|
+
|
|
47
|
+
Empty repositories, interrupted rebases, linked worktrees, submodules, binary and >5 MB
|
|
48
|
+
files, renames, and paths with spaces, quotes, CJK or emoji are handled explicitly.
|
|
49
|
+
difftab is deliberately a viewer: no editing, history, blame or review workflow
|
|
50
|
+
([out-of-scope list](CONTRIBUTING.md#the-read-only-promise-is-not-negotiable)).
|
|
83
51
|
|
|
84
52
|
## Never writes to your repository
|
|
85
53
|
|
|
86
|
-
Not a best-effort claim
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
1. **Command allowlist.** The whole flow runs under `GIT_TRACE`, and every git
|
|
91
|
-
invocation the product makes — including subprocesses git spawns internally, such as
|
|
92
|
-
an accidental `gc` — is asserted to be one of `status` / `diff` / `rev-parse` /
|
|
93
|
-
`ls-files` / `version`. A positive assertion checks the trace is not empty, so the
|
|
94
|
-
allowlist can never pass against nothing.
|
|
95
|
-
2. **`.git` is byte-for-byte unchanged.** The flow runs once against a read-only `.git`,
|
|
96
|
-
and once against a writable one with a before/after snapshot of every file (size,
|
|
97
|
-
mtime, content digest). A control run proves the snapshot would have caught a change.
|
|
98
|
-
|
|
99
|
-
The backend is also auditable by hand: `dist/server/main.js` ships unminified precisely
|
|
100
|
-
so you can read which git commands it runs.
|
|
101
|
-
|
|
102
|
-
## Local security
|
|
103
|
-
|
|
104
|
-
The server binds `127.0.0.1` on a random port with a session token, and every request —
|
|
105
|
-
including SSE and static assets — passes three checks *before* anything else is decided:
|
|
106
|
-
|
|
107
|
-
- **`Host`** must be `127.0.0.1:<port>` or `localhost:<port>`. This, not the token, is the
|
|
108
|
-
real defence against DNS rebinding.
|
|
109
|
-
- **`Origin`**, when present, must be the server's own. No CORS headers are ever sent.
|
|
110
|
-
- **Token**, bound to this session's port, so a token that leaks to another localhost
|
|
111
|
-
service (cookies are scoped by host, not by port) cannot be replayed there.
|
|
112
|
-
|
|
113
|
-
The token arrives in the URL once and is immediately swapped for an `HttpOnly;
|
|
114
|
-
SameSite=Strict` cookie with a 302 that strips the query, so it does not linger in browser
|
|
115
|
-
history. Responses carry a strict CSP (`default-src 'none'`, plus `frame-ancestors` /
|
|
116
|
-
`base-uri` / `form-action`, which do not fall back to it), `Cache-Control: no-store` and
|
|
117
|
-
`X-Content-Type-Options: nosniff`. Static assets are served from an in-memory allowlist,
|
|
118
|
-
never by joining a request path onto a directory. There is no environment variable or code
|
|
119
|
-
branch that relaxes any of this.
|
|
120
|
-
|
|
121
|
-
## Platform support
|
|
122
|
-
|
|
123
|
-
macOS, Windows and Linux are all supported and all tested. CI runs the full smoke suite
|
|
124
|
-
across three platforms × Node 22 / 24 / 26, plus dedicated jobs for global installation,
|
|
125
|
-
the Node version guard, and degrading to polling when the inotify quota is exhausted.
|
|
126
|
-
What CI cannot cover is in [Known limitations](#known-limitations), below.
|
|
127
|
-
|
|
128
|
-
## Known limitations
|
|
129
|
-
|
|
130
|
-
- **The token is passed on a command line.** argv is readable by other users on the same
|
|
131
|
-
machine, so launching the browser opens a window of tens of milliseconds — one that
|
|
132
|
-
requires an attacker already logged in locally, polling in a tight loop. Closing it
|
|
133
|
-
properly conflicts with reusing a running instance, so it is revisited after 0.1.0. How
|
|
134
|
-
wide it is under `xdg-open` is deliberately *not* measured in CI: a headless number
|
|
135
|
-
would be reassuring and meaningless.
|
|
136
|
-
- **The browser actually appearing on a Windows or Linux desktop is not covered by CI.**
|
|
137
|
-
Runners have no desktop session, so the *choice* of `open` / `cmd /c start ""` /
|
|
138
|
-
`xdg-open` and its argv are asserted, but not the window. Both of these wait on a first
|
|
139
|
-
real user.
|
|
54
|
+
Not a best-effort claim: difftab only ever runs read-only git commands — no stage, commit,
|
|
55
|
+
discard, pull, push, branch or stash. Two gates enforce it on every change: a `GIT_TRACE`
|
|
56
|
+
allowlist over every git invocation, and a byte-for-byte comparison of `.git` before and
|
|
57
|
+
after. And `dist/server/main.js` ships unminified, so you can audit it by hand.
|
|
140
58
|
|
|
141
59
|
## Development
|
|
142
60
|
|
|
143
61
|
```bash
|
|
144
|
-
pnpm install --frozen-lockfile
|
|
62
|
+
pnpm install --frozen-lockfile
|
|
145
63
|
pnpm build # frontend (Vite) + backend (tsdown)
|
|
146
64
|
node bin/difftab.js # run it against any repository
|
|
147
65
|
```
|
|
148
66
|
|
|
149
|
-
[CONTRIBUTING.md](CONTRIBUTING.md) has the
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
truth — they change before the code does.
|
|
67
|
+
[CONTRIBUTING.md](CONTRIBUTING.md) has the dev-server setup, the gates, and the things
|
|
68
|
+
that fail silently rather than loudly; [`docs/`](docs/README.md) holds requirements and
|
|
69
|
+
design, the single source of truth.
|
|
153
70
|
|
|
154
71
|
## License
|
|
155
72
|
|
package/README.zh-CN.md
CHANGED
|
@@ -1,136 +1,58 @@
|
|
|
1
1
|
# difftab
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/difftab)
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
关掉标签页,进程自行退出。
|
|
5
|
+
**一个标签页,看懂 AI 编码 Agent 改了哪些代码。**
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
在仓库目录敲一条命令,本地网页随即打开,只读展示当前工作区的 diff 与分支状态(就是 `git status` 与 `git diff HEAD` 的内容),并在 agent 继续写的过程中自动刷新;关掉标签页,进程自行退出。
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
开一场代码评审。它展示的就是 `git status` 与 `git diff HEAD` 的内容,以并排 diff 加语法
|
|
12
|
-
高亮呈现,并在 agent 继续写的过程中自动刷新。它对你的仓库**全程零写操作**——这是核心承诺,
|
|
13
|
-
由两道 CI 门禁守着,详见[下文](#全程零写操作)。
|
|
9
|
+
[English](README.md)
|
|
14
10
|
|
|
15
11
|
## 安装
|
|
16
12
|
|
|
17
|
-
不用装,在任意仓库目录里直接跑:
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
npx difftab # pnpm 用户:pnpm dlx difftab
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
首次要下载解包,多花几秒,之后走缓存。
|
|
24
|
-
|
|
25
|
-
如果你每次 agent 跑完都要看一眼,那就装一次——`npx` 光是决定该跑哪个版本,就比 difftab
|
|
26
|
-
自己启动还花时间:
|
|
27
|
-
|
|
28
13
|
```bash
|
|
29
|
-
|
|
14
|
+
npx difftab # 或者装一次:npm i -g difftab
|
|
30
15
|
```
|
|
31
16
|
|
|
32
|
-
要求 **Node.js 22
|
|
33
|
-
就打进产物,所以全局安装是零传递依赖的。
|
|
17
|
+
要求 **Node.js 22 或更高**,macOS / Windows / Linux 三端均支持,零依赖。
|
|
34
18
|
|
|
35
19
|
## 使用
|
|
36
20
|
|
|
37
21
|
```bash
|
|
38
22
|
cd /path/to/your/repo
|
|
39
|
-
difftab
|
|
23
|
+
difftab
|
|
40
24
|
```
|
|
41
25
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
| `-v`, `--version` | 打印版本号并退出 |
|
|
46
|
-
| `-h`, `--help` | 打印帮助并退出 |
|
|
26
|
+
- `--no-open`——只打印 URL,不拉起浏览器
|
|
27
|
+
- `-v`, `--version`——打印版本号并退出
|
|
28
|
+
- `-h`, `--help`——打印帮助并退出
|
|
47
29
|
|
|
48
|
-
|
|
30
|
+
在同一个仓库里再敲一次,会复用已在跑的实例。
|
|
49
31
|
|
|
50
32
|
## 能看到什么
|
|
51
33
|
|
|
52
|
-
-
|
|
53
|
-
|
|
54
|
-
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
-
|
|
58
|
-
中的 rebase / merge / cherry-pick / revert / bisect / `git am` 各出一个标注。
|
|
59
|
-
- **自动刷新** —— 文件监听经 SSE 推到前端,agent 边改你边看。在递归监听会耗尽整机
|
|
60
|
-
inotify 配额的场合(Linux + Node < 24.14.0),改用轮询,并在界面上标注出来;轮询期间改
|
|
61
|
-
一个**未跟踪**文件的内容不会刷新页面(未跟踪条目在 `git status` 里只有一行,内容变了它
|
|
62
|
-
一个字节都不变)。
|
|
63
|
-
- **自己退出** —— 最后一个标签页关掉 45 秒后自动退。多标签、刷新页面、系统休眠唤醒、浏览
|
|
64
|
-
器丢弃后台标签都不会误触发。
|
|
65
|
-
|
|
66
|
-
边界情况是被显式处理的,而不是留着崩:空仓库(还没有提交)、游离 HEAD、停在中途的 rebase、
|
|
67
|
-
linked worktree、submodule、二进制文件、超过 5MB 的文件、重命名(标注完整旧路径与相似度)、
|
|
68
|
-
删除的文件,以及路径里带空格、引号、中日韩文字或 emoji 的文件。
|
|
69
|
-
|
|
70
|
-
difftab 刻意只是个查看器:不编辑代码、不看历史、不做 blame、不承载评审流程。完整的不做
|
|
71
|
-
清单在 [CONTRIBUTING.md](CONTRIBUTING.md#the-read-only-promise-is-not-negotiable) 与
|
|
72
|
-
[`docs/spec.md`](docs/spec.md) §4。
|
|
73
|
-
|
|
74
|
-
## 全程零写操作
|
|
34
|
+
- **变更列表**——已暂存、未暂存、未跟踪、冲突四组,未跟踪的目录展开到文件粒度。
|
|
35
|
+
- **按文件懒加载的 diff**——点开某个文件才取它的补丁,渲染用 [diff2html](https://diff2html.xyz/) + highlight.js,配色仿 VS Code,面板窄到放不下两列时自动切成逐行。
|
|
36
|
+
- **分支状态**——当前分支、ahead/behind 计数、无上游、游离 HEAD,以及进行中的 rebase /
|
|
37
|
+
merge / cherry-pick / revert / bisect / `git am`。
|
|
38
|
+
- **自动刷新**——文件监听经 SSE 推到前端;递归监听会耗尽 inotify 配额的场合改用轮询,并在界面上标注。
|
|
39
|
+
- **自己退出**——最后一个标签页关掉 45 秒后自动退。
|
|
75
40
|
|
|
76
|
-
|
|
77
|
-
不 stash——它只发只读的 git 命令。这条由两道互相独立的门禁在每次 CI、三个平台上守着:
|
|
41
|
+
空仓库、停在中途的 rebase、linked worktree、submodule、二进制与超过 5MB 的文件、重命名,以及带空格、引号、中日韩文字或 emoji 的路径,都是被显式处理的。difftab 刻意只是个查看器:不编辑、不看历史、不做 blame、不承载评审流程(完整的不做清单见 [CONTRIBUTING.md](CONTRIBUTING.md#the-read-only-promise-is-not-negotiable))。
|
|
78
42
|
|
|
79
|
-
|
|
80
|
-
自己内部再起的子进程(比如一次意外触发的 `gc`)——都被断言只能是 `status` / `diff` /
|
|
81
|
-
`rev-parse` / `ls-files` / `version`。另配一条「确实记到了东西」的正面断言,白名单不会
|
|
82
|
-
对着一个空数组通过。
|
|
83
|
-
2. **`.git` 逐字节不变。** 同一条流程跑两遍:一遍对着只读的 `.git`,一遍对着可写的
|
|
84
|
-
`.git` 并在前后各拍一次快照(每个文件的 size、mtime、内容摘要)比对。另有一组正面对照
|
|
85
|
-
证明这份快照真的抓得住变化。
|
|
86
|
-
|
|
87
|
-
后端也支持手工审计:`dist/server/main.js` **不压缩不混淆**发布,就是为了让你自己读一遍它
|
|
88
|
-
到底跑了哪些 git 命令。
|
|
89
|
-
|
|
90
|
-
## 本地安全
|
|
91
|
-
|
|
92
|
-
服务绑定 `127.0.0.1`,随机端口 + 会话级 token。每一个请求——包括 SSE 与静态资源——都要先
|
|
93
|
-
过三道校验,**排在其余一切判定之前**:
|
|
94
|
-
|
|
95
|
-
- **`Host`** 必须是 `127.0.0.1:<端口>` 或 `localhost:<端口>`。挡住 DNS rebinding 的是这一
|
|
96
|
-
道,不是 token。
|
|
97
|
-
- **`Origin`** 非空时必须是服务自身。所有响应不带任何 CORS 头。
|
|
98
|
-
- **token** 与本次会话的端口绑定——cookie 的作用域是 host 而非 origin,不隔离端口,绑上
|
|
99
|
-
端口后即使 token 漏给了同机另一个 localhost 服务,也没法在别处复用。
|
|
100
|
-
|
|
101
|
-
token 只在 URL 里出现一次,首访即置换成 `HttpOnly; SameSite=Strict` cookie 并 302 掉
|
|
102
|
-
query,不会长期滞留在浏览器历史里。响应带严格 CSP(`default-src 'none'`,外加不回退到它的
|
|
103
|
-
`frame-ancestors` / `base-uri` / `form-action`),以及 `Cache-Control: no-store` 与
|
|
104
|
-
`X-Content-Type-Options: nosniff`。静态资源按内存里的白名单映射,绝不用请求路径去拼目录。
|
|
105
|
-
**后端不存在任何放宽上述校验的环境变量或分支。**
|
|
106
|
-
|
|
107
|
-
## 平台支持
|
|
108
|
-
|
|
109
|
-
macOS / Windows / Linux 三端均支持、均有测试。CI 在三平台 × Node 22 / 24 / 26 上跑完整冒烟
|
|
110
|
-
套件,另有全局安装、Node 版本守卫、inotify 配额耗尽降级三个专用作业。CI 覆盖不到的部分在
|
|
111
|
-
下面的[已知边界](#已知边界)。
|
|
112
|
-
|
|
113
|
-
## 已知边界
|
|
43
|
+
## 全程零写操作
|
|
114
44
|
|
|
115
|
-
|
|
116
|
-
窗口——而它要求攻击者已经以另一个本机用户身份在紧循环轮询。真正关掉它与「再敲一次命令
|
|
117
|
-
复用已有实例」相冲突,留到 0.1.0 之后再看。这个窗口在 `xdg-open` 下有多宽**刻意不在 CI
|
|
118
|
-
里量**:headless 上量出来的数字会让人放心,但没有意义。
|
|
119
|
-
- **浏览器在 Windows / Linux 桌面上真的弹出来,CI 覆盖不到。** runner 没有桌面会话,所以
|
|
120
|
-
`open` / `cmd /c start ""` / `xdg-open` 的**选择与 argv** 有断言,窗口本身没有。这两条
|
|
121
|
-
都等首个真实用户。
|
|
45
|
+
不是「尽量」:difftab 只发只读的 git 命令——不 stage、不 commit、不 discard、不 pull / push、不建分支、不 stash。两道门禁在每次改动上守着:一道是覆盖每一次 git 调用的 `GIT_TRACE` 命令白名单,另一道是 `.git` 前后逐字节比对。后端也支持手工审计:`dist/server/main.js` 不压缩不混淆发布。
|
|
122
46
|
|
|
123
47
|
## 开发
|
|
124
48
|
|
|
125
49
|
```bash
|
|
126
|
-
pnpm install --frozen-lockfile
|
|
50
|
+
pnpm install --frozen-lockfile
|
|
127
51
|
pnpm build # 前端 Vite + 后端 tsdown
|
|
128
52
|
node bin/difftab.js # 在任意 git 仓库目录下跑起来
|
|
129
53
|
```
|
|
130
54
|
|
|
131
|
-
其余在 [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
132
|
-
里那几条「坏了不报错」的地方。需求与设计的唯一事实来源是 [`docs/`](docs/README.md)——需求要
|
|
133
|
-
变,先改 docs 再改代码。
|
|
55
|
+
其余在 [CONTRIBUTING.md](CONTRIBUTING.md):dev server 怎么起、门禁清单,以及那几条「坏了不报错」的地方;需求与设计的唯一事实来源是 [`docs/`](docs/README.md)。
|
|
134
56
|
|
|
135
57
|
## License
|
|
136
58
|
|
package/dist/server/main.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { closeSync, mkdirSync, openSync, readFileSync, realpathSync, statSync, unlinkSync, watch, writeFileSync, writeSync } from "node:fs";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
3
|
import { parseArgs } from "node:util";
|
|
4
|
-
import { isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
4
|
+
import { basename, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
5
5
|
import { spawn } from "node:child_process";
|
|
6
6
|
import { createServer, request } from "node:http";
|
|
7
7
|
import { homedir, tmpdir } from "node:os";
|
|
@@ -267,6 +267,23 @@ async function locateRepo(cwd) {
|
|
|
267
267
|
};
|
|
268
268
|
}
|
|
269
269
|
/**
|
|
270
|
+
* 工作区根目录名 —— 页面标题里的项目标识(§5.4 / §5.12 的 `RepoState.repoName`)。
|
|
271
|
+
*
|
|
272
|
+
* **和 `root` 住在一起,不在消费者那边现切**:下面那条「用 `node:path` 不手写切分」
|
|
273
|
+
* 的理由整个建立在 `root` 是怎么来的之上(`rev-parse --show-toplevel`),而那件事只有
|
|
274
|
+
* 本文件知道。放在 `http/` 里的话,这里改一次 `root` 的产出方式,那边的论证就静默过期。
|
|
275
|
+
*
|
|
276
|
+
* **用 `node:path` 的 `basename`,不要自己切 `/`**:Windows 上 `--show-toplevel` 回的是
|
|
277
|
+
* `C:/…` 正斜杠,而 win32 的 basename 两种分隔符都认;POSIX 上 `\` 是合法文件名字符,
|
|
278
|
+
* posix 的 basename 不会误把它当分隔符。两个平台各有一半是手写切分挑不对的。
|
|
279
|
+
*
|
|
280
|
+
* 根目录没有 basename 时(`/`、Windows 盘符根)回空串,**不编一个名字出来** ——
|
|
281
|
+
* 「取不到时显示什么」是展示决定,归消费者(见 `shared/protocol.ts`)。
|
|
282
|
+
*/
|
|
283
|
+
function repoNameOf(repo) {
|
|
284
|
+
return basename(repo.root);
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
270
287
|
* diff 的基准。
|
|
271
288
|
*
|
|
272
289
|
* 正常仓库是 `HEAD`;空仓库(尚无任何提交)下 HEAD 不存在,`git diff HEAD` 会 fatal,
|
|
@@ -1575,6 +1592,7 @@ async function startServer(repo, options = {}) {
|
|
|
1575
1592
|
message: sanitizeMessage(message, repo.root)
|
|
1576
1593
|
} });
|
|
1577
1594
|
};
|
|
1595
|
+
const repoName = repoNameOf(repo);
|
|
1578
1596
|
const secret = createSecret();
|
|
1579
1597
|
let token = "";
|
|
1580
1598
|
let port = 0;
|
|
@@ -1721,6 +1739,7 @@ async function startServer(repo, options = {}) {
|
|
|
1721
1739
|
case "/api/state": {
|
|
1722
1740
|
const status = await readStatus(repo);
|
|
1723
1741
|
sendJson(res, 200, {
|
|
1742
|
+
repoName,
|
|
1724
1743
|
branch: status.branch,
|
|
1725
1744
|
files: status.files,
|
|
1726
1745
|
watch: currentWatchState()
|
package/dist/web/app.css
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
|
|
2
|
-
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after{--tw-border-style:solid;--tw-font-weight:initial;--tw-outline-style:solid}::backdrop{--tw-border-style:solid;--tw-font-weight:initial;--tw-outline-style:solid}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, -apple-system, "Segoe UI", "Noto Sans", "PingFang SC", "Microsoft YaHei", sans-serif;--font-mono:ui-monospace, "SF Mono", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--font-weight-medium:500;--radius-sm:.25rem;--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-editor-background:#fff;--color-editor-foreground:#3b3b3b;--color-side-bar-background:#f8f8f8;--color-side-bar-section-header-background:#f0f0f0;--color-title-bar-background:#f8f8f8;--color-panel-border:#e5e5e5;--color-description-foreground:#6f6f6f;--color-focus-border:#005fb8;--color-text-link-foreground:#005fb8;--color-list-hover-background:#e8e8e8;--color-list-active-selection-background:#e4e6f1;--color-list-active-selection-foreground:#000;--color-warning-background:#fdf6d3;--color-warning-border:#b89500;--color-git-modified:#895503;--color-git-deleted:#ad0707;--color-git-added:#587c0c;--color-git-untracked:#007100;--color-git-conflicting:#ad0707;--color-diff-inserted-background:#9bb95533;--color-diff-inserted-text-background:#9bb95573;--color-diff-inserted-border:#9bb95580;--color-diff-removed-background:#ff000029;--color-diff-removed-text-background:#ff000052;--color-diff-removed-border:#ff000059;--color-diff-diagonal-fill:#0000000f}}@layer base{*,:after,:before{box-sizing:border-box;border:0 solid;margin:0;padding:0}::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.top-0{top:0}.ml-1{margin-left:var(--spacing)}.contents{display:contents}.flex{display:flex}.h-screen{height:100vh}.min-h-0{min-height:0}.w-5{width:calc(var(--spacing) * 5)}.w-80{width:calc(var(--spacing) * 80)}.w-full{width:100%}.max-w-60{max-width:calc(var(--spacing) * 60)}.min-w-0{min-width:0}.flex-1{flex:1}.shrink-0{flex-shrink:0}.flex-col{flex-direction:column}.items-baseline{align-items:baseline}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.rounded-sm{border-radius:var(--radius-sm)}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-panel-border{border-color:var(--color-panel-border)}.border-warning-border{border-color:var(--color-warning-border)}.bg-editor-background{background-color:var(--color-editor-background)}.bg-list-active-selection-background{background-color:var(--color-list-active-selection-background)}.bg-side-bar-background{background-color:var(--color-side-bar-background)}.bg-side-bar-section-header-background{background-color:var(--color-side-bar-section-header-background)}.bg-title-bar-background{background-color:var(--color-title-bar-background)}.bg-warning-background{background-color:var(--color-warning-background)}.p-4{padding:calc(var(--spacing) * 4)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-2{padding-block:calc(var(--spacing) * 2)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.break-all{word-break:break-all}.text-description-foreground{color:var(--color-description-foreground)}.text-editor-foreground{color:var(--color-editor-foreground)}.text-git-added{color:var(--color-git-added)}.text-git-conflicting{color:var(--color-git-conflicting)}.text-git-deleted{color:var(--color-git-deleted)}.text-git-modified{color:var(--color-git-modified)}.text-git-untracked{color:var(--color-git-untracked)}.text-list-active-selection-foreground{color:var(--color-list-active-selection-foreground)}@media (hover:hover){.hover\:bg-list-hover-background:hover{background-color:var(--color-list-hover-background)}}.focus-visible\:outline-2:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px}.focus-visible\:-outline-offset-2:focus-visible{outline-offset:calc(2px * -1)}.focus-visible\:outline-focus-border:focus-visible{outline-color:var(--color-focus-border)}}pre code.hljs{padding:1em;display:block;overflow-x:auto}code.hljs{padding:3px 5px}.hljs{color:#24292e;background:#fff}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#d73a49}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#6f42c1}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-variable,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id{color:#005cc5}.hljs-regexp,.hljs-string,.hljs-meta .hljs-string{color:#032f62}.hljs-built_in,.hljs-symbol{color:#e36209}.hljs-comment,.hljs-code,.hljs-formula{color:#6a737d}.hljs-name,.hljs-quote,.hljs-selector-tag,.hljs-selector-pseudo{color:#22863a}.hljs-subst{color:#24292e}.hljs-section{color:#005cc5;font-weight:700}.hljs-bullet{color:#735c0f}.hljs-emphasis{color:#24292e;font-style:italic}.hljs-strong{color:#24292e;font-weight:700}.hljs-addition{color:#22863a;background-color:#f0fff4}.hljs-deletion{color:#b31d28;background-color:#ffeef0}@media (prefers-color-scheme:dark){pre code.hljs{padding:1em;display:block;overflow-x:auto}code.hljs{padding:3px 5px}.hljs{color:#c9d1d9;background:#0d1117}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#ff7b72}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#d2a8ff}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-variable,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id{color:#79c0ff}.hljs-regexp,.hljs-string,.hljs-meta .hljs-string{color:#a5d6ff}.hljs-built_in,.hljs-symbol{color:#ffa657}.hljs-comment,.hljs-code,.hljs-formula{color:#8b949e}.hljs-name,.hljs-quote,.hljs-selector-tag,.hljs-selector-pseudo{color:#7ee787}.hljs-subst{color:#c9d1d9}.hljs-section{color:#1f6feb;font-weight:700}.hljs-bullet{color:#f2cc60}.hljs-emphasis{color:#c9d1d9;font-style:italic}.hljs-strong{color:#c9d1d9;font-weight:700}.hljs-addition{color:#aff5b4;background-color:#033a16}.hljs-deletion{color:#ffdcd7;background-color:#67060c}}:host,:root{--d2h-bg-color:#fff;--d2h-border-color:#ddd;--d2h-dim-color:#0000004d;--d2h-line-border-color:#eee;--d2h-file-header-bg-color:#f7f7f7;--d2h-file-header-border-color:#d8d8d8;--d2h-empty-placeholder-bg-color:#f1f1f1;--d2h-empty-placeholder-border-color:#e1e1e1;--d2h-selected-color:#c8e1ff;--d2h-ins-bg-color:#dfd;--d2h-ins-border-color:#b4e2b4;--d2h-ins-highlight-bg-color:#97f295;--d2h-ins-label-color:#399839;--d2h-del-bg-color:#fee8e9;--d2h-del-border-color:#e9aeae;--d2h-del-highlight-bg-color:#ffb6ba;--d2h-del-label-color:#c33;--d2h-change-del-color:#fdf2d0;--d2h-change-ins-color:#ded;--d2h-info-bg-color:#f8fafd;--d2h-info-border-color:#d5e4f2;--d2h-change-label-color:#d0b44c;--d2h-moved-label-color:#3572b0;--d2h-dark-color:#e6edf3;--d2h-dark-bg-color:#0d1117;--d2h-dark-border-color:#30363d;--d2h-dark-dim-color:#6e7681;--d2h-dark-line-border-color:#21262d;--d2h-dark-file-header-bg-color:#161b22;--d2h-dark-file-header-border-color:#30363d;--d2h-dark-empty-placeholder-bg-color:#6e76811a;--d2h-dark-empty-placeholder-border-color:#30363d;--d2h-dark-selected-color:#388bfd1a;--d2h-dark-ins-bg-color:#2ea04326;--d2h-dark-ins-border-color:#2ea04366;--d2h-dark-ins-highlight-bg-color:#2ea04366;--d2h-dark-ins-label-color:#3fb950;--d2h-dark-del-bg-color:#f851491a;--d2h-dark-del-border-color:#f8514966;--d2h-dark-del-highlight-bg-color:#f8514966;--d2h-dark-del-label-color:#f85149;--d2h-dark-change-del-color:#d2992233;--d2h-dark-change-ins-color:#2ea04340;--d2h-dark-info-bg-color:#388bfd1a;--d2h-dark-info-border-color:#388bfd66;--d2h-dark-change-label-color:#d29922;--d2h-dark-moved-label-color:#3572b0}.d2h-wrapper{text-align:left}.d2h-file-header{background-color:#f7f7f7;background-color:var(--d2h-file-header-bg-color);border-bottom:1px solid #d8d8d8;border-bottom:1px solid var(--d2h-file-header-border-color);height:35px;padding:5px 10px;font-family:Source Sans Pro,Helvetica Neue,Helvetica,Arial,sans-serif;display:flex}.d2h-file-header.d2h-sticky-header{z-index:1;position:sticky;top:0}.d2h-file-stats{margin-left:auto;font-size:14px;display:flex}.d2h-lines-added{border:1px solid #b4e2b4;border:1px solid var(--d2h-ins-border-color);color:var(--d2h-ins-label-color);text-align:right;vertical-align:middle;border-radius:5px 0 0 5px;padding:2px}.d2h-lines-deleted{border:1px solid #e9aeae;border:1px solid var(--d2h-del-border-color);color:var(--d2h-del-label-color);text-align:left;vertical-align:middle;border-radius:0 5px 5px 0;margin-left:1px;padding:2px}.d2h-file-name-wrapper{align-items:center;width:100%;font-size:15px;display:flex}.d2h-file-name{text-overflow:ellipsis;white-space:nowrap;overflow-x:hidden}.d2h-file-wrapper{border:1px solid #ddd;border:1px solid var(--d2h-border-color);border-radius:3px;margin-bottom:1em}.d2h-file-collapse{cursor:pointer;border:1px solid #ddd;border:1px solid var(--d2h-border-color);border-radius:3px;justify-content:flex-end;align-items:center;padding:4px 8px;font-size:12px;display:none}.d2h-file-collapse.d2h-selected{background-color:#c8e1ff;background-color:var(--d2h-selected-color)}.d2h-file-collapse-input{margin:0 4px 0 0}.d2h-diff-table{border-collapse:collapse;width:100%;font-family:Menlo,Consolas,monospace;font-size:13px}.d2h-files-diff{width:100%;display:flex}.d2h-file-diff{overflow-y:hidden}.d2h-file-diff.d2h-d-none,.d2h-files-diff.d2h-d-none{display:none}.d2h-file-side-diff{width:50%;display:inline-block;overflow:scroll hidden}.d2h-code-line{width:calc(100% - 16em);padding:0 8em}.d2h-code-line,.d2h-code-side-line{-webkit-user-select:none;user-select:none;white-space:nowrap;display:inline-block}.d2h-code-side-line{width:calc(100% - 9em);padding:0 4.5em}.d2h-code-line-ctn{word-wrap:normal;-webkit-user-select:text;user-select:text;vertical-align:middle;white-space:pre;background:0 0;width:100%;padding:0;display:inline-block}.d2h-code-line del,.d2h-code-side-line del{background-color:#ffb6ba;background-color:var(--d2h-del-highlight-bg-color)}.d2h-code-line del,.d2h-code-line ins,.d2h-code-side-line del,.d2h-code-side-line ins{border-radius:.2em;margin-top:-1px;-webkit-text-decoration:none;text-decoration:none;display:inline-block}.d2h-code-line ins,.d2h-code-side-line ins{background-color:#97f295;background-color:var(--d2h-ins-highlight-bg-color);text-align:left}.d2h-code-line-prefix{word-wrap:normal;white-space:pre;background:0 0;padding:0;display:inline}.line-num1{float:left}.line-num1,.line-num2{box-sizing:border-box;text-overflow:ellipsis;width:3.5em;padding:0 .5em;overflow:hidden}.line-num2{float:right}.d2h-code-linenumber{background-color:#fff;background-color:var(--d2h-bg-color);border:solid #eee;border:solid var(--d2h-line-border-color);box-sizing:border-box;color:var(--d2h-dim-color);cursor:pointer;text-align:right;border-width:0 1px;width:7.5em;display:inline-block;position:absolute}.d2h-code-linenumber:after{content:""}.d2h-code-side-linenumber{background-color:#fff;background-color:var(--d2h-bg-color);border:solid #eee;border:solid var(--d2h-line-border-color);box-sizing:border-box;color:var(--d2h-dim-color);cursor:pointer;text-align:right;text-overflow:ellipsis;border-width:0 1px;width:4em;padding:0 .5em;display:inline-block;position:absolute;overflow:hidden}.d2h-code-side-linenumber:after{content:""}.d2h-code-side-emptyplaceholder,.d2h-emptyplaceholder{background-color:#f1f1f1;background-color:var(--d2h-empty-placeholder-bg-color);border-color:#e1e1e1;border-color:var(--d2h-empty-placeholder-border-color)}.d2h-code-line-prefix,.d2h-code-linenumber,.d2h-code-side-linenumber,.d2h-emptyplaceholder{-webkit-user-select:none;user-select:none}.d2h-code-linenumber,.d2h-code-side-linenumber{direction:rtl}.d2h-del{background-color:#fee8e9;background-color:var(--d2h-del-bg-color);border-color:#e9aeae;border-color:var(--d2h-del-border-color)}.d2h-ins{background-color:#dfd;background-color:var(--d2h-ins-bg-color);border-color:#b4e2b4;border-color:var(--d2h-ins-border-color)}.d2h-info{background-color:#f8fafd;background-color:var(--d2h-info-bg-color);border-color:#d5e4f2;border-color:var(--d2h-info-border-color);color:var(--d2h-dim-color)}.d2h-file-diff .d2h-del.d2h-change{background-color:#fdf2d0;background-color:var(--d2h-change-del-color)}.d2h-file-diff .d2h-ins.d2h-change{background-color:#ded;background-color:var(--d2h-change-ins-color)}.d2h-file-list-wrapper{margin-bottom:10px}.d2h-file-list-wrapper a{-webkit-text-decoration:none;text-decoration:none}.d2h-file-list-wrapper a,.d2h-file-list-wrapper a:visited{color:var(--d2h-moved-label-color)}.d2h-file-list-header{text-align:left}.d2h-file-list-title{font-weight:700}.d2h-file-list-line{text-align:left;display:flex}.d2h-file-list{margin:0;padding:0;list-style:none;display:block}.d2h-file-list>li{border-bottom:1px solid #ddd;border-bottom:1px solid var(--d2h-border-color);margin:0;padding:5px 10px}.d2h-file-list>li:last-child{border-bottom:none}.d2h-file-switch{cursor:pointer;font-size:10px;display:none}.d2h-icon{fill:currentColor;vertical-align:middle;margin-right:10px}.d2h-deleted{color:var(--d2h-del-label-color)}.d2h-added{color:var(--d2h-ins-label-color)}.d2h-changed{color:var(--d2h-change-label-color)}.d2h-moved{color:var(--d2h-moved-label-color)}.d2h-tag{background-color:#fff;background-color:var(--d2h-bg-color);margin-left:5px;padding:0 2px;font-size:10px;display:flex}.d2h-deleted-tag{border:1px solid #c33;border:1px solid var(--d2h-del-label-color)}.d2h-added-tag{border:1px solid #399839;border:1px solid var(--d2h-ins-label-color)}.d2h-changed-tag{border:1px solid #d0b44c;border:1px solid var(--d2h-change-label-color)}.d2h-moved-tag{border:1px solid #3572b0;border:1px solid var(--d2h-moved-label-color)}.d2h-dark-color-scheme{background-color:#0d1117;background-color:var(--d2h-dark-bg-color);color:var(--d2h-dark-color)}.d2h-dark-color-scheme .d2h-file-header{background-color:#161b22;background-color:var(--d2h-dark-file-header-bg-color);border-bottom:#30363d;border-bottom:var(--d2h-dark-file-header-border-color)}.d2h-dark-color-scheme .d2h-lines-added{border:1px solid #2ea04366;border:1px solid var(--d2h-dark-ins-border-color);color:var(--d2h-dark-ins-label-color)}.d2h-dark-color-scheme .d2h-lines-deleted{border:1px solid #f8514966;border:1px solid var(--d2h-dark-del-border-color);color:var(--d2h-dark-del-label-color)}.d2h-dark-color-scheme .d2h-code-line del,.d2h-dark-color-scheme .d2h-code-side-line del{background-color:#f8514966;background-color:var(--d2h-dark-del-highlight-bg-color)}.d2h-dark-color-scheme .d2h-code-line ins,.d2h-dark-color-scheme .d2h-code-side-line ins{background-color:#2ea04366;background-color:var(--d2h-dark-ins-highlight-bg-color)}.d2h-dark-color-scheme .d2h-diff-tbody{border-color:#30363d;border-color:var(--d2h-dark-border-color)}.d2h-dark-color-scheme .d2h-code-side-linenumber{background-color:#0d1117;background-color:var(--d2h-dark-bg-color);border-color:#21262d;border-color:var(--d2h-dark-line-border-color);color:var(--d2h-dark-dim-color)}.d2h-dark-color-scheme .d2h-files-diff .d2h-code-side-emptyplaceholder,.d2h-dark-color-scheme .d2h-files-diff .d2h-emptyplaceholder{background-color:#6e76811a;background-color:var(--d2h-dark-empty-placeholder-bg-color);border-color:#30363d;border-color:var(--d2h-dark-empty-placeholder-border-color)}.d2h-dark-color-scheme .d2h-code-linenumber{background-color:#0d1117;background-color:var(--d2h-dark-bg-color);border-color:#21262d;border-color:var(--d2h-dark-line-border-color);color:var(--d2h-dark-dim-color)}.d2h-dark-color-scheme .d2h-del{background-color:#f851491a;background-color:var(--d2h-dark-del-bg-color);border-color:#f8514966;border-color:var(--d2h-dark-del-border-color)}.d2h-dark-color-scheme .d2h-ins{background-color:#2ea04326;background-color:var(--d2h-dark-ins-bg-color);border-color:#2ea04366;border-color:var(--d2h-dark-ins-border-color)}.d2h-dark-color-scheme .d2h-info{background-color:#388bfd1a;background-color:var(--d2h-dark-info-bg-color);border-color:#388bfd66;border-color:var(--d2h-dark-info-border-color);color:var(--d2h-dark-dim-color)}.d2h-dark-color-scheme .d2h-file-diff .d2h-del.d2h-change{background-color:#d2992233;background-color:var(--d2h-dark-change-del-color)}.d2h-dark-color-scheme .d2h-file-diff .d2h-ins.d2h-change{background-color:#2ea04340;background-color:var(--d2h-dark-change-ins-color)}.d2h-dark-color-scheme .d2h-file-wrapper{border:1px solid #30363d;border:1px solid var(--d2h-dark-border-color)}.d2h-dark-color-scheme .d2h-file-collapse{border:1px solid #0d1117;border:1px solid var(--d2h-dark-bg-color)}.d2h-dark-color-scheme .d2h-file-collapse.d2h-selected{background-color:#388bfd1a;background-color:var(--d2h-dark-selected-color)}.d2h-dark-color-scheme .d2h-file-list-wrapper a,.d2h-dark-color-scheme .d2h-file-list-wrapper a:visited{color:var(--d2h-dark-moved-label-color)}.d2h-dark-color-scheme .d2h-file-list>li{border-bottom:1px solid #0d1117;border-bottom:1px solid var(--d2h-dark-bg-color)}.d2h-dark-color-scheme .d2h-deleted{color:var(--d2h-dark-del-label-color)}.d2h-dark-color-scheme .d2h-added{color:var(--d2h-dark-ins-label-color)}.d2h-dark-color-scheme .d2h-changed{color:var(--d2h-dark-change-label-color)}.d2h-dark-color-scheme .d2h-moved{color:var(--d2h-dark-moved-label-color)}.d2h-dark-color-scheme .d2h-tag{background-color:#0d1117;background-color:var(--d2h-dark-bg-color)}.d2h-dark-color-scheme .d2h-deleted-tag{border:1px solid #f85149;border:1px solid var(--d2h-dark-del-label-color)}.d2h-dark-color-scheme .d2h-added-tag{border:1px solid #3fb950;border:1px solid var(--d2h-dark-ins-label-color)}.d2h-dark-color-scheme .d2h-changed-tag{border:1px solid #d29922;border:1px solid var(--d2h-dark-change-label-color)}.d2h-dark-color-scheme .d2h-moved-tag{border:1px solid #3572b0;border:1px solid var(--d2h-dark-moved-label-color)}@media (prefers-color-scheme:dark){.d2h-auto-color-scheme{background-color:#0d1117;background-color:var(--d2h-dark-bg-color);color:var(--d2h-dark-color)}.d2h-auto-color-scheme .d2h-file-header{background-color:#161b22;background-color:var(--d2h-dark-file-header-bg-color);border-bottom:#30363d;border-bottom:var(--d2h-dark-file-header-border-color)}.d2h-auto-color-scheme .d2h-lines-added{border:1px solid #2ea04366;border:1px solid var(--d2h-dark-ins-border-color);color:var(--d2h-dark-ins-label-color)}.d2h-auto-color-scheme .d2h-lines-deleted{border:1px solid #f8514966;border:1px solid var(--d2h-dark-del-border-color);color:var(--d2h-dark-del-label-color)}.d2h-auto-color-scheme .d2h-code-line del,.d2h-auto-color-scheme .d2h-code-side-line del{background-color:#f8514966;background-color:var(--d2h-dark-del-highlight-bg-color)}.d2h-auto-color-scheme .d2h-code-line ins,.d2h-auto-color-scheme .d2h-code-side-line ins{background-color:#2ea04366;background-color:var(--d2h-dark-ins-highlight-bg-color)}.d2h-auto-color-scheme .d2h-diff-tbody{border-color:#30363d;border-color:var(--d2h-dark-border-color)}.d2h-auto-color-scheme .d2h-code-side-linenumber{background-color:#0d1117;background-color:var(--d2h-dark-bg-color);border-color:#21262d;border-color:var(--d2h-dark-line-border-color);color:var(--d2h-dark-dim-color)}.d2h-auto-color-scheme .d2h-files-diff .d2h-code-side-emptyplaceholder,.d2h-auto-color-scheme .d2h-files-diff .d2h-emptyplaceholder{background-color:#6e76811a;background-color:var(--d2h-dark-empty-placeholder-bg-color);border-color:#30363d;border-color:var(--d2h-dark-empty-placeholder-border-color)}.d2h-auto-color-scheme .d2h-code-linenumber{background-color:#0d1117;background-color:var(--d2h-dark-bg-color);border-color:#21262d;border-color:var(--d2h-dark-line-border-color);color:var(--d2h-dark-dim-color)}.d2h-auto-color-scheme .d2h-del{background-color:#f851491a;background-color:var(--d2h-dark-del-bg-color);border-color:#f8514966;border-color:var(--d2h-dark-del-border-color)}.d2h-auto-color-scheme .d2h-ins{background-color:#2ea04326;background-color:var(--d2h-dark-ins-bg-color);border-color:#2ea04366;border-color:var(--d2h-dark-ins-border-color)}.d2h-auto-color-scheme .d2h-info{background-color:#388bfd1a;background-color:var(--d2h-dark-info-bg-color);border-color:#388bfd66;border-color:var(--d2h-dark-info-border-color);color:var(--d2h-dark-dim-color)}.d2h-auto-color-scheme .d2h-file-diff .d2h-del.d2h-change{background-color:#d2992233;background-color:var(--d2h-dark-change-del-color)}.d2h-auto-color-scheme .d2h-file-diff .d2h-ins.d2h-change{background-color:#2ea04340;background-color:var(--d2h-dark-change-ins-color)}.d2h-auto-color-scheme .d2h-file-wrapper{border:1px solid #30363d;border:1px solid var(--d2h-dark-border-color)}.d2h-auto-color-scheme .d2h-file-collapse{border:1px solid #0d1117;border:1px solid var(--d2h-dark-bg-color)}.d2h-auto-color-scheme .d2h-file-collapse.d2h-selected{background-color:#388bfd1a;background-color:var(--d2h-dark-selected-color)}.d2h-auto-color-scheme .d2h-file-list-wrapper a,.d2h-auto-color-scheme .d2h-file-list-wrapper a:visited{color:var(--d2h-dark-moved-label-color)}.d2h-auto-color-scheme .d2h-file-list>li{border-bottom:1px solid #0d1117;border-bottom:1px solid var(--d2h-dark-bg-color)}.d2h-dark-color-scheme .d2h-deleted{color:var(--d2h-dark-del-label-color)}.d2h-auto-color-scheme .d2h-added{color:var(--d2h-dark-ins-label-color)}.d2h-auto-color-scheme .d2h-changed{color:var(--d2h-dark-change-label-color)}.d2h-auto-color-scheme .d2h-moved{color:var(--d2h-dark-moved-label-color)}.d2h-auto-color-scheme .d2h-tag{background-color:#0d1117;background-color:var(--d2h-dark-bg-color)}.d2h-auto-color-scheme .d2h-deleted-tag{border:1px solid #f85149;border:1px solid var(--d2h-dark-del-label-color)}.d2h-auto-color-scheme .d2h-added-tag{border:1px solid #3fb950;border:1px solid var(--d2h-dark-ins-label-color)}.d2h-auto-color-scheme .d2h-changed-tag{border:1px solid #d29922;border:1px solid var(--d2h-dark-change-label-color)}.d2h-auto-color-scheme .d2h-moved-tag{border:1px solid #3572b0;border:1px solid var(--d2h-dark-moved-label-color)}}:root{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light dark}@media (prefers-color-scheme:dark){:root{--lightningcss-light: ;--lightningcss-dark:initial;--color-editor-background:#1f1f1f;--color-editor-foreground:#ccc;--color-side-bar-background:#181818;--color-side-bar-section-header-background:#202020;--color-title-bar-background:#181818;--color-panel-border:#2b2b2b;--color-description-foreground:#9d9d9d;--color-focus-border:#0078d4;--color-text-link-foreground:#4daafc;--color-list-hover-background:#2a2d2e;--color-list-active-selection-background:#04395e;--color-list-active-selection-foreground:#fff;--color-warning-background:#352a05;--color-git-modified:#e2c08d;--color-git-deleted:#c74e39;--color-git-added:#81b88b;--color-git-untracked:#73c991;--color-git-conflicting:#e4676b;--color-diff-diagonal-fill:#ffffff0f}}:root{--gg-d2h-map:1;--d2h-bg-color:var(--color-editor-background);--d2h-border-color:var(--color-panel-border);--d2h-dim-color:var(--color-description-foreground);--d2h-line-border-color:var(--color-panel-border);--d2h-file-header-bg-color:var(--color-side-bar-section-header-background);--d2h-file-header-border-color:var(--color-panel-border);--d2h-info-bg-color:var(--color-side-bar-background);--d2h-info-border-color:var(--color-panel-border);--d2h-empty-placeholder-bg-color:var(--color-diff-diagonal-fill);--d2h-empty-placeholder-border-color:var(--color-panel-border);--d2h-selected-color:var(--color-list-active-selection-background);--d2h-ins-bg-color:var(--color-diff-inserted-background);--d2h-ins-highlight-bg-color:var(--color-diff-inserted-text-background);--d2h-ins-border-color:var(--color-diff-inserted-border);--d2h-ins-label-color:var(--color-git-added);--d2h-del-bg-color:var(--color-diff-removed-background);--d2h-del-highlight-bg-color:var(--color-diff-removed-text-background);--d2h-del-border-color:var(--color-diff-removed-border);--d2h-del-label-color:var(--color-git-deleted);--d2h-change-del-color:var(--color-diff-removed-background);--d2h-change-ins-color:var(--color-diff-inserted-background);--d2h-change-label-color:var(--color-git-modified);--d2h-moved-label-color:var(--color-text-link-foreground)}body{background-color:var(--color-editor-background);color:var(--color-editor-foreground)}.d2h-diff-table{font-family:var(--font-mono)}.d2h-file-header{font-family:var(--font-sans)}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}
|
|
2
|
+
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-font-weight:initial;--tw-outline-style:solid}::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-font-weight:initial;--tw-outline-style:solid}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, -apple-system, "Segoe UI", "Noto Sans", "PingFang SC", "Microsoft YaHei", sans-serif;--font-mono:ui-monospace, "SF Mono", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--font-weight-medium:500;--radius-sm:.25rem;--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-editor-background:#fff;--color-editor-foreground:#3b3b3b;--color-side-bar-background:#f8f8f8;--color-side-bar-section-header-background:#f0f0f0;--color-title-bar-background:#f8f8f8;--color-panel-border:#e5e5e5;--color-description-foreground:#6f6f6f;--color-focus-border:#005fb8;--color-text-link-foreground:#005fb8;--color-list-hover-background:#e8e8e8;--color-list-active-selection-background:#e4e6f1;--color-list-active-selection-foreground:#000;--color-warning-background:#fdf6d3;--color-warning-border:#b89500;--color-git-modified:#895503;--color-git-deleted:#ad0707;--color-git-added:#587c0c;--color-git-untracked:#007100;--color-git-conflicting:#ad0707;--color-diff-inserted-background:#9bb95533;--color-diff-inserted-text-background:#9bb95573;--color-diff-inserted-border:#9bb95580;--color-diff-removed-background:#ff000029;--color-diff-removed-text-background:#ff000052;--color-diff-removed-border:#ff000059;--color-diff-diagonal-fill:#0000000f}}@layer base{*,:after,:before{box-sizing:border-box;border:0 solid;margin:0;padding:0}::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.top-0{top:0}.ml-1{margin-left:var(--spacing)}.ml-2{margin-left:calc(var(--spacing) * 2)}.contents{display:contents}.flex{display:flex}.h-screen{height:100vh}.min-h-0{min-height:0}.w-5{width:calc(var(--spacing) * 5)}.w-80{width:calc(var(--spacing) * 80)}.w-full{width:100%}.max-w-60{max-width:calc(var(--spacing) * 60)}.min-w-0{min-width:0}.flex-1{flex:1}.shrink-0{flex-shrink:0}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.flex-col{flex-direction:column}.items-baseline{align-items:baseline}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.rounded-sm{border-radius:var(--radius-sm)}.border{border-style:var(--tw-border-style);border-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-panel-border{border-color:var(--color-panel-border)}.border-warning-border{border-color:var(--color-warning-border)}.bg-editor-background{background-color:var(--color-editor-background)}.bg-list-active-selection-background{background-color:var(--color-list-active-selection-background)}.bg-side-bar-background{background-color:var(--color-side-bar-background)}.bg-side-bar-section-header-background{background-color:var(--color-side-bar-section-header-background)}.bg-title-bar-background{background-color:var(--color-title-bar-background)}.bg-warning-background{background-color:var(--color-warning-background)}.p-4{padding:calc(var(--spacing) * 4)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-2{padding-block:calc(var(--spacing) * 2)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.break-all{word-break:break-all}.text-description-foreground{color:var(--color-description-foreground)}.text-editor-foreground{color:var(--color-editor-foreground)}.text-git-added{color:var(--color-git-added)}.text-git-conflicting{color:var(--color-git-conflicting)}.text-git-deleted{color:var(--color-git-deleted)}.text-git-modified{color:var(--color-git-modified)}.text-git-untracked{color:var(--color-git-untracked)}.text-list-active-selection-foreground{color:var(--color-list-active-selection-foreground)}@media (hover:hover){.hover\:bg-list-hover-background:hover{background-color:var(--color-list-hover-background)}}.focus-visible\:outline-2:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px}.focus-visible\:-outline-offset-2:focus-visible{outline-offset:calc(2px * -1)}.focus-visible\:outline-focus-border:focus-visible{outline-color:var(--color-focus-border)}}pre code.hljs{padding:1em;display:block;overflow-x:auto}code.hljs{padding:3px 5px}.hljs{color:#24292e;background:#fff}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#d73a49}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#6f42c1}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-variable,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id{color:#005cc5}.hljs-regexp,.hljs-string,.hljs-meta .hljs-string{color:#032f62}.hljs-built_in,.hljs-symbol{color:#e36209}.hljs-comment,.hljs-code,.hljs-formula{color:#6a737d}.hljs-name,.hljs-quote,.hljs-selector-tag,.hljs-selector-pseudo{color:#22863a}.hljs-subst{color:#24292e}.hljs-section{color:#005cc5;font-weight:700}.hljs-bullet{color:#735c0f}.hljs-emphasis{color:#24292e;font-style:italic}.hljs-strong{color:#24292e;font-weight:700}.hljs-addition{color:#22863a;background-color:#f0fff4}.hljs-deletion{color:#b31d28;background-color:#ffeef0}@media (prefers-color-scheme:dark){pre code.hljs{padding:1em;display:block;overflow-x:auto}code.hljs{padding:3px 5px}.hljs{color:#c9d1d9;background:#0d1117}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#ff7b72}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#d2a8ff}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-variable,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id{color:#79c0ff}.hljs-regexp,.hljs-string,.hljs-meta .hljs-string{color:#a5d6ff}.hljs-built_in,.hljs-symbol{color:#ffa657}.hljs-comment,.hljs-code,.hljs-formula{color:#8b949e}.hljs-name,.hljs-quote,.hljs-selector-tag,.hljs-selector-pseudo{color:#7ee787}.hljs-subst{color:#c9d1d9}.hljs-section{color:#1f6feb;font-weight:700}.hljs-bullet{color:#f2cc60}.hljs-emphasis{color:#c9d1d9;font-style:italic}.hljs-strong{color:#c9d1d9;font-weight:700}.hljs-addition{color:#aff5b4;background-color:#033a16}.hljs-deletion{color:#ffdcd7;background-color:#67060c}}:host,:root{--d2h-bg-color:#fff;--d2h-border-color:#ddd;--d2h-dim-color:#0000004d;--d2h-line-border-color:#eee;--d2h-file-header-bg-color:#f7f7f7;--d2h-file-header-border-color:#d8d8d8;--d2h-empty-placeholder-bg-color:#f1f1f1;--d2h-empty-placeholder-border-color:#e1e1e1;--d2h-selected-color:#c8e1ff;--d2h-ins-bg-color:#dfd;--d2h-ins-border-color:#b4e2b4;--d2h-ins-highlight-bg-color:#97f295;--d2h-ins-label-color:#399839;--d2h-del-bg-color:#fee8e9;--d2h-del-border-color:#e9aeae;--d2h-del-highlight-bg-color:#ffb6ba;--d2h-del-label-color:#c33;--d2h-change-del-color:#fdf2d0;--d2h-change-ins-color:#ded;--d2h-info-bg-color:#f8fafd;--d2h-info-border-color:#d5e4f2;--d2h-change-label-color:#d0b44c;--d2h-moved-label-color:#3572b0;--d2h-dark-color:#e6edf3;--d2h-dark-bg-color:#0d1117;--d2h-dark-border-color:#30363d;--d2h-dark-dim-color:#6e7681;--d2h-dark-line-border-color:#21262d;--d2h-dark-file-header-bg-color:#161b22;--d2h-dark-file-header-border-color:#30363d;--d2h-dark-empty-placeholder-bg-color:#6e76811a;--d2h-dark-empty-placeholder-border-color:#30363d;--d2h-dark-selected-color:#388bfd1a;--d2h-dark-ins-bg-color:#2ea04326;--d2h-dark-ins-border-color:#2ea04366;--d2h-dark-ins-highlight-bg-color:#2ea04366;--d2h-dark-ins-label-color:#3fb950;--d2h-dark-del-bg-color:#f851491a;--d2h-dark-del-border-color:#f8514966;--d2h-dark-del-highlight-bg-color:#f8514966;--d2h-dark-del-label-color:#f85149;--d2h-dark-change-del-color:#d2992233;--d2h-dark-change-ins-color:#2ea04340;--d2h-dark-info-bg-color:#388bfd1a;--d2h-dark-info-border-color:#388bfd66;--d2h-dark-change-label-color:#d29922;--d2h-dark-moved-label-color:#3572b0}.d2h-wrapper{text-align:left}.d2h-file-header{background-color:#f7f7f7;background-color:var(--d2h-file-header-bg-color);border-bottom:1px solid #d8d8d8;border-bottom:1px solid var(--d2h-file-header-border-color);height:35px;padding:5px 10px;font-family:Source Sans Pro,Helvetica Neue,Helvetica,Arial,sans-serif;display:flex}.d2h-file-header.d2h-sticky-header{z-index:1;position:sticky;top:0}.d2h-file-stats{margin-left:auto;font-size:14px;display:flex}.d2h-lines-added{border:1px solid #b4e2b4;border:1px solid var(--d2h-ins-border-color);color:var(--d2h-ins-label-color);text-align:right;vertical-align:middle;border-radius:5px 0 0 5px;padding:2px}.d2h-lines-deleted{border:1px solid #e9aeae;border:1px solid var(--d2h-del-border-color);color:var(--d2h-del-label-color);text-align:left;vertical-align:middle;border-radius:0 5px 5px 0;margin-left:1px;padding:2px}.d2h-file-name-wrapper{align-items:center;width:100%;font-size:15px;display:flex}.d2h-file-name{text-overflow:ellipsis;white-space:nowrap;overflow-x:hidden}.d2h-file-wrapper{border:1px solid #ddd;border:1px solid var(--d2h-border-color);border-radius:3px;margin-bottom:1em}.d2h-file-collapse{cursor:pointer;border:1px solid #ddd;border:1px solid var(--d2h-border-color);border-radius:3px;justify-content:flex-end;align-items:center;padding:4px 8px;font-size:12px;display:none}.d2h-file-collapse.d2h-selected{background-color:#c8e1ff;background-color:var(--d2h-selected-color)}.d2h-file-collapse-input{margin:0 4px 0 0}.d2h-diff-table{border-collapse:collapse;width:100%;font-family:Menlo,Consolas,monospace;font-size:13px}.d2h-files-diff{width:100%;display:flex}.d2h-file-diff{overflow-y:hidden}.d2h-file-diff.d2h-d-none,.d2h-files-diff.d2h-d-none{display:none}.d2h-file-side-diff{width:50%;display:inline-block;overflow:scroll hidden}.d2h-code-line{width:calc(100% - 16em);padding:0 8em}.d2h-code-line,.d2h-code-side-line{-webkit-user-select:none;user-select:none;white-space:nowrap;display:inline-block}.d2h-code-side-line{width:calc(100% - 9em);padding:0 4.5em}.d2h-code-line-ctn{word-wrap:normal;-webkit-user-select:text;user-select:text;vertical-align:middle;white-space:pre;background:0 0;width:100%;padding:0;display:inline-block}.d2h-code-line del,.d2h-code-side-line del{background-color:#ffb6ba;background-color:var(--d2h-del-highlight-bg-color)}.d2h-code-line del,.d2h-code-line ins,.d2h-code-side-line del,.d2h-code-side-line ins{border-radius:.2em;margin-top:-1px;-webkit-text-decoration:none;text-decoration:none;display:inline-block}.d2h-code-line ins,.d2h-code-side-line ins{background-color:#97f295;background-color:var(--d2h-ins-highlight-bg-color);text-align:left}.d2h-code-line-prefix{word-wrap:normal;white-space:pre;background:0 0;padding:0;display:inline}.line-num1{float:left}.line-num1,.line-num2{box-sizing:border-box;text-overflow:ellipsis;width:3.5em;padding:0 .5em;overflow:hidden}.line-num2{float:right}.d2h-code-linenumber{background-color:#fff;background-color:var(--d2h-bg-color);border:solid #eee;border:solid var(--d2h-line-border-color);box-sizing:border-box;color:var(--d2h-dim-color);cursor:pointer;text-align:right;border-width:0 1px;width:7.5em;display:inline-block;position:absolute}.d2h-code-linenumber:after{content:""}.d2h-code-side-linenumber{background-color:#fff;background-color:var(--d2h-bg-color);border:solid #eee;border:solid var(--d2h-line-border-color);box-sizing:border-box;color:var(--d2h-dim-color);cursor:pointer;text-align:right;text-overflow:ellipsis;border-width:0 1px;width:4em;padding:0 .5em;display:inline-block;position:absolute;overflow:hidden}.d2h-code-side-linenumber:after{content:""}.d2h-code-side-emptyplaceholder,.d2h-emptyplaceholder{background-color:#f1f1f1;background-color:var(--d2h-empty-placeholder-bg-color);border-color:#e1e1e1;border-color:var(--d2h-empty-placeholder-border-color)}.d2h-code-line-prefix,.d2h-code-linenumber,.d2h-code-side-linenumber,.d2h-emptyplaceholder{-webkit-user-select:none;user-select:none}.d2h-code-linenumber,.d2h-code-side-linenumber{direction:rtl}.d2h-del{background-color:#fee8e9;background-color:var(--d2h-del-bg-color);border-color:#e9aeae;border-color:var(--d2h-del-border-color)}.d2h-ins{background-color:#dfd;background-color:var(--d2h-ins-bg-color);border-color:#b4e2b4;border-color:var(--d2h-ins-border-color)}.d2h-info{background-color:#f8fafd;background-color:var(--d2h-info-bg-color);border-color:#d5e4f2;border-color:var(--d2h-info-border-color);color:var(--d2h-dim-color)}.d2h-file-diff .d2h-del.d2h-change{background-color:#fdf2d0;background-color:var(--d2h-change-del-color)}.d2h-file-diff .d2h-ins.d2h-change{background-color:#ded;background-color:var(--d2h-change-ins-color)}.d2h-file-list-wrapper{margin-bottom:10px}.d2h-file-list-wrapper a{-webkit-text-decoration:none;text-decoration:none}.d2h-file-list-wrapper a,.d2h-file-list-wrapper a:visited{color:var(--d2h-moved-label-color)}.d2h-file-list-header{text-align:left}.d2h-file-list-title{font-weight:700}.d2h-file-list-line{text-align:left;display:flex}.d2h-file-list{margin:0;padding:0;list-style:none;display:block}.d2h-file-list>li{border-bottom:1px solid #ddd;border-bottom:1px solid var(--d2h-border-color);margin:0;padding:5px 10px}.d2h-file-list>li:last-child{border-bottom:none}.d2h-file-switch{cursor:pointer;font-size:10px;display:none}.d2h-icon{fill:currentColor;vertical-align:middle;margin-right:10px}.d2h-deleted{color:var(--d2h-del-label-color)}.d2h-added{color:var(--d2h-ins-label-color)}.d2h-changed{color:var(--d2h-change-label-color)}.d2h-moved{color:var(--d2h-moved-label-color)}.d2h-tag{background-color:#fff;background-color:var(--d2h-bg-color);margin-left:5px;padding:0 2px;font-size:10px;display:flex}.d2h-deleted-tag{border:1px solid #c33;border:1px solid var(--d2h-del-label-color)}.d2h-added-tag{border:1px solid #399839;border:1px solid var(--d2h-ins-label-color)}.d2h-changed-tag{border:1px solid #d0b44c;border:1px solid var(--d2h-change-label-color)}.d2h-moved-tag{border:1px solid #3572b0;border:1px solid var(--d2h-moved-label-color)}.d2h-dark-color-scheme{background-color:#0d1117;background-color:var(--d2h-dark-bg-color);color:var(--d2h-dark-color)}.d2h-dark-color-scheme .d2h-file-header{background-color:#161b22;background-color:var(--d2h-dark-file-header-bg-color);border-bottom:#30363d;border-bottom:var(--d2h-dark-file-header-border-color)}.d2h-dark-color-scheme .d2h-lines-added{border:1px solid #2ea04366;border:1px solid var(--d2h-dark-ins-border-color);color:var(--d2h-dark-ins-label-color)}.d2h-dark-color-scheme .d2h-lines-deleted{border:1px solid #f8514966;border:1px solid var(--d2h-dark-del-border-color);color:var(--d2h-dark-del-label-color)}.d2h-dark-color-scheme .d2h-code-line del,.d2h-dark-color-scheme .d2h-code-side-line del{background-color:#f8514966;background-color:var(--d2h-dark-del-highlight-bg-color)}.d2h-dark-color-scheme .d2h-code-line ins,.d2h-dark-color-scheme .d2h-code-side-line ins{background-color:#2ea04366;background-color:var(--d2h-dark-ins-highlight-bg-color)}.d2h-dark-color-scheme .d2h-diff-tbody{border-color:#30363d;border-color:var(--d2h-dark-border-color)}.d2h-dark-color-scheme .d2h-code-side-linenumber{background-color:#0d1117;background-color:var(--d2h-dark-bg-color);border-color:#21262d;border-color:var(--d2h-dark-line-border-color);color:var(--d2h-dark-dim-color)}.d2h-dark-color-scheme .d2h-files-diff .d2h-code-side-emptyplaceholder,.d2h-dark-color-scheme .d2h-files-diff .d2h-emptyplaceholder{background-color:#6e76811a;background-color:var(--d2h-dark-empty-placeholder-bg-color);border-color:#30363d;border-color:var(--d2h-dark-empty-placeholder-border-color)}.d2h-dark-color-scheme .d2h-code-linenumber{background-color:#0d1117;background-color:var(--d2h-dark-bg-color);border-color:#21262d;border-color:var(--d2h-dark-line-border-color);color:var(--d2h-dark-dim-color)}.d2h-dark-color-scheme .d2h-del{background-color:#f851491a;background-color:var(--d2h-dark-del-bg-color);border-color:#f8514966;border-color:var(--d2h-dark-del-border-color)}.d2h-dark-color-scheme .d2h-ins{background-color:#2ea04326;background-color:var(--d2h-dark-ins-bg-color);border-color:#2ea04366;border-color:var(--d2h-dark-ins-border-color)}.d2h-dark-color-scheme .d2h-info{background-color:#388bfd1a;background-color:var(--d2h-dark-info-bg-color);border-color:#388bfd66;border-color:var(--d2h-dark-info-border-color);color:var(--d2h-dark-dim-color)}.d2h-dark-color-scheme .d2h-file-diff .d2h-del.d2h-change{background-color:#d2992233;background-color:var(--d2h-dark-change-del-color)}.d2h-dark-color-scheme .d2h-file-diff .d2h-ins.d2h-change{background-color:#2ea04340;background-color:var(--d2h-dark-change-ins-color)}.d2h-dark-color-scheme .d2h-file-wrapper{border:1px solid #30363d;border:1px solid var(--d2h-dark-border-color)}.d2h-dark-color-scheme .d2h-file-collapse{border:1px solid #0d1117;border:1px solid var(--d2h-dark-bg-color)}.d2h-dark-color-scheme .d2h-file-collapse.d2h-selected{background-color:#388bfd1a;background-color:var(--d2h-dark-selected-color)}.d2h-dark-color-scheme .d2h-file-list-wrapper a,.d2h-dark-color-scheme .d2h-file-list-wrapper a:visited{color:var(--d2h-dark-moved-label-color)}.d2h-dark-color-scheme .d2h-file-list>li{border-bottom:1px solid #0d1117;border-bottom:1px solid var(--d2h-dark-bg-color)}.d2h-dark-color-scheme .d2h-deleted{color:var(--d2h-dark-del-label-color)}.d2h-dark-color-scheme .d2h-added{color:var(--d2h-dark-ins-label-color)}.d2h-dark-color-scheme .d2h-changed{color:var(--d2h-dark-change-label-color)}.d2h-dark-color-scheme .d2h-moved{color:var(--d2h-dark-moved-label-color)}.d2h-dark-color-scheme .d2h-tag{background-color:#0d1117;background-color:var(--d2h-dark-bg-color)}.d2h-dark-color-scheme .d2h-deleted-tag{border:1px solid #f85149;border:1px solid var(--d2h-dark-del-label-color)}.d2h-dark-color-scheme .d2h-added-tag{border:1px solid #3fb950;border:1px solid var(--d2h-dark-ins-label-color)}.d2h-dark-color-scheme .d2h-changed-tag{border:1px solid #d29922;border:1px solid var(--d2h-dark-change-label-color)}.d2h-dark-color-scheme .d2h-moved-tag{border:1px solid #3572b0;border:1px solid var(--d2h-dark-moved-label-color)}@media (prefers-color-scheme:dark){.d2h-auto-color-scheme{background-color:#0d1117;background-color:var(--d2h-dark-bg-color);color:var(--d2h-dark-color)}.d2h-auto-color-scheme .d2h-file-header{background-color:#161b22;background-color:var(--d2h-dark-file-header-bg-color);border-bottom:#30363d;border-bottom:var(--d2h-dark-file-header-border-color)}.d2h-auto-color-scheme .d2h-lines-added{border:1px solid #2ea04366;border:1px solid var(--d2h-dark-ins-border-color);color:var(--d2h-dark-ins-label-color)}.d2h-auto-color-scheme .d2h-lines-deleted{border:1px solid #f8514966;border:1px solid var(--d2h-dark-del-border-color);color:var(--d2h-dark-del-label-color)}.d2h-auto-color-scheme .d2h-code-line del,.d2h-auto-color-scheme .d2h-code-side-line del{background-color:#f8514966;background-color:var(--d2h-dark-del-highlight-bg-color)}.d2h-auto-color-scheme .d2h-code-line ins,.d2h-auto-color-scheme .d2h-code-side-line ins{background-color:#2ea04366;background-color:var(--d2h-dark-ins-highlight-bg-color)}.d2h-auto-color-scheme .d2h-diff-tbody{border-color:#30363d;border-color:var(--d2h-dark-border-color)}.d2h-auto-color-scheme .d2h-code-side-linenumber{background-color:#0d1117;background-color:var(--d2h-dark-bg-color);border-color:#21262d;border-color:var(--d2h-dark-line-border-color);color:var(--d2h-dark-dim-color)}.d2h-auto-color-scheme .d2h-files-diff .d2h-code-side-emptyplaceholder,.d2h-auto-color-scheme .d2h-files-diff .d2h-emptyplaceholder{background-color:#6e76811a;background-color:var(--d2h-dark-empty-placeholder-bg-color);border-color:#30363d;border-color:var(--d2h-dark-empty-placeholder-border-color)}.d2h-auto-color-scheme .d2h-code-linenumber{background-color:#0d1117;background-color:var(--d2h-dark-bg-color);border-color:#21262d;border-color:var(--d2h-dark-line-border-color);color:var(--d2h-dark-dim-color)}.d2h-auto-color-scheme .d2h-del{background-color:#f851491a;background-color:var(--d2h-dark-del-bg-color);border-color:#f8514966;border-color:var(--d2h-dark-del-border-color)}.d2h-auto-color-scheme .d2h-ins{background-color:#2ea04326;background-color:var(--d2h-dark-ins-bg-color);border-color:#2ea04366;border-color:var(--d2h-dark-ins-border-color)}.d2h-auto-color-scheme .d2h-info{background-color:#388bfd1a;background-color:var(--d2h-dark-info-bg-color);border-color:#388bfd66;border-color:var(--d2h-dark-info-border-color);color:var(--d2h-dark-dim-color)}.d2h-auto-color-scheme .d2h-file-diff .d2h-del.d2h-change{background-color:#d2992233;background-color:var(--d2h-dark-change-del-color)}.d2h-auto-color-scheme .d2h-file-diff .d2h-ins.d2h-change{background-color:#2ea04340;background-color:var(--d2h-dark-change-ins-color)}.d2h-auto-color-scheme .d2h-file-wrapper{border:1px solid #30363d;border:1px solid var(--d2h-dark-border-color)}.d2h-auto-color-scheme .d2h-file-collapse{border:1px solid #0d1117;border:1px solid var(--d2h-dark-bg-color)}.d2h-auto-color-scheme .d2h-file-collapse.d2h-selected{background-color:#388bfd1a;background-color:var(--d2h-dark-selected-color)}.d2h-auto-color-scheme .d2h-file-list-wrapper a,.d2h-auto-color-scheme .d2h-file-list-wrapper a:visited{color:var(--d2h-dark-moved-label-color)}.d2h-auto-color-scheme .d2h-file-list>li{border-bottom:1px solid #0d1117;border-bottom:1px solid var(--d2h-dark-bg-color)}.d2h-dark-color-scheme .d2h-deleted{color:var(--d2h-dark-del-label-color)}.d2h-auto-color-scheme .d2h-added{color:var(--d2h-dark-ins-label-color)}.d2h-auto-color-scheme .d2h-changed{color:var(--d2h-dark-change-label-color)}.d2h-auto-color-scheme .d2h-moved{color:var(--d2h-dark-moved-label-color)}.d2h-auto-color-scheme .d2h-tag{background-color:#0d1117;background-color:var(--d2h-dark-bg-color)}.d2h-auto-color-scheme .d2h-deleted-tag{border:1px solid #f85149;border:1px solid var(--d2h-dark-del-label-color)}.d2h-auto-color-scheme .d2h-added-tag{border:1px solid #3fb950;border:1px solid var(--d2h-dark-ins-label-color)}.d2h-auto-color-scheme .d2h-changed-tag{border:1px solid #d29922;border:1px solid var(--d2h-dark-change-label-color)}.d2h-auto-color-scheme .d2h-moved-tag{border:1px solid #3572b0;border:1px solid var(--d2h-dark-moved-label-color)}}:root{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light dark}@media (prefers-color-scheme:dark){:root{--lightningcss-light: ;--lightningcss-dark:initial;--color-editor-background:#1f1f1f;--color-editor-foreground:#ccc;--color-side-bar-background:#181818;--color-side-bar-section-header-background:#202020;--color-title-bar-background:#181818;--color-panel-border:#2b2b2b;--color-description-foreground:#9d9d9d;--color-focus-border:#0078d4;--color-text-link-foreground:#4daafc;--color-list-hover-background:#2a2d2e;--color-list-active-selection-background:#04395e;--color-list-active-selection-foreground:#fff;--color-warning-background:#352a05;--color-git-modified:#e2c08d;--color-git-deleted:#c74e39;--color-git-added:#81b88b;--color-git-untracked:#73c991;--color-git-conflicting:#e4676b;--color-diff-diagonal-fill:#ffffff0f}}:root{--gg-d2h-map:1;--d2h-bg-color:var(--color-editor-background);--d2h-border-color:var(--color-panel-border);--d2h-dim-color:var(--color-description-foreground);--d2h-line-border-color:var(--color-panel-border);--d2h-file-header-bg-color:var(--color-side-bar-section-header-background);--d2h-file-header-border-color:var(--color-panel-border);--d2h-info-bg-color:var(--color-side-bar-background);--d2h-info-border-color:var(--color-panel-border);--d2h-empty-placeholder-bg-color:var(--color-diff-diagonal-fill);--d2h-empty-placeholder-border-color:var(--color-panel-border);--d2h-selected-color:var(--color-list-active-selection-background);--d2h-ins-bg-color:var(--color-diff-inserted-background);--d2h-ins-highlight-bg-color:var(--color-diff-inserted-text-background);--d2h-ins-border-color:var(--color-diff-inserted-border);--d2h-ins-label-color:var(--color-git-added);--d2h-del-bg-color:var(--color-diff-removed-background);--d2h-del-highlight-bg-color:var(--color-diff-removed-text-background);--d2h-del-border-color:var(--color-diff-removed-border);--d2h-del-label-color:var(--color-git-deleted);--d2h-change-del-color:var(--color-diff-removed-background);--d2h-change-ins-color:var(--color-diff-inserted-background);--d2h-change-label-color:var(--color-git-modified);--d2h-moved-label-color:var(--color-text-link-foreground)}body{background-color:var(--color-editor-background);color:var(--color-editor-foreground)}.d2h-diff-table{font-family:var(--font-mono)}.d2h-file-header{display:none}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}
|
|
3
3
|
/*$vite$:1*/
|