diffprism 0.20.1 → 0.21.0
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 +36 -8
- package/dist/bin.js +2 -2
- package/dist/{chunk-L2D5SDUV.js → chunk-3IVV6O45.js} +42 -1
- package/dist/mcp-server.js +2 -2
- package/package.json +1 -1
- package/ui-dist/assets/index-7eOJS8DL.css +1 -0
- package/ui-dist/assets/{index-C_k3uWX-.js → index-BQiD8ibP.js} +19 -19
- package/ui-dist/index.html +2 -2
- package/ui-dist/assets/index-CkUXOfXP.css +0 -1
package/README.md
CHANGED
|
@@ -12,11 +12,12 @@ DiffPrism gives you a visual review step for AI-written code — stage your chan
|
|
|
12
12
|
- **Review briefing bar** — summary stats, complexity scoring, test coverage gaps, pattern flags, and dependency tracking
|
|
13
13
|
- **Agent reasoning panel** — see why the AI made each change
|
|
14
14
|
- **Dark/light mode** — toggle with theme persistence
|
|
15
|
-
- **Keyboard shortcuts** — `j`/`k` navigate files, `s` cycles file status
|
|
15
|
+
- **Keyboard shortcuts** — `j`/`k` navigate files, `s` cycles file status, `Cmd/Ctrl+Enter` saves comments, `?` toggles hotkey guide
|
|
16
16
|
- **Three-way decisions** — approve, request changes, or approve with comments
|
|
17
17
|
- **Branch display** — current git branch shown in the review header
|
|
18
18
|
- **Global server mode** — `diffprism server` runs a persistent multi-session review server, multiple agents post reviews to one browser tab
|
|
19
|
-
- **Multi-session UI** — session list with status badges, branch info, file counts, and change stats
|
|
19
|
+
- **Multi-session UI** — session list with live status badges, branch info, file counts, and change stats; stale sessions auto-expire
|
|
20
|
+
- **One-command setup & teardown** — `diffprism setup` configures Claude Code integration, `diffprism teardown` cleanly reverses it
|
|
20
21
|
|
|
21
22
|
## Quick Start
|
|
22
23
|
|
|
@@ -37,6 +38,14 @@ This single command configures everything:
|
|
|
37
38
|
|
|
38
39
|
After running, restart Claude Code. The first time you use `/review`, Claude will ask your preferences and save them to `diffprism.config.json`.
|
|
39
40
|
|
|
41
|
+
To remove DiffPrism from a project:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx diffprism teardown
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
This reverses all changes made by `setup`: removes DiffPrism entries from `.mcp.json`, permissions, hooks, the skill file, `.gitignore`, and the `.diffprism/` directory. Non-DiffPrism entries are preserved.
|
|
48
|
+
|
|
40
49
|
See the [full setup guide](docs/claude-setup.md) for manual configuration, Claude Desktop config, troubleshooting, and advanced options.
|
|
41
50
|
|
|
42
51
|
### Use from the CLI
|
|
@@ -64,6 +73,18 @@ diffprism review --staged --title "Add auth middleware"
|
|
|
64
73
|
|
|
65
74
|
A browser window opens with the diff viewer. Review the changes and click **Approve**, **Request Changes**, or **Approve with Comments**.
|
|
66
75
|
|
|
76
|
+
### Quick Start (setup + watch in one command)
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# Configure Claude Code integration and start watching in one step
|
|
80
|
+
diffprism start
|
|
81
|
+
|
|
82
|
+
# With flags
|
|
83
|
+
diffprism start --staged --title "Working on auth"
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
This runs `diffprism setup` (silently, if already configured) then starts watch mode. Ideal for first-time use or when switching projects.
|
|
87
|
+
|
|
67
88
|
### Watch Mode (live-updating)
|
|
68
89
|
|
|
69
90
|
Keep a persistent browser tab that auto-refreshes as files change — ideal for reviewing while an agent is working:
|
|
@@ -102,13 +123,16 @@ diffprism server status
|
|
|
102
123
|
diffprism server stop
|
|
103
124
|
```
|
|
104
125
|
|
|
105
|
-
When the global server is running, MCP tools automatically detect it and route reviews there instead of opening ephemeral browser tabs. Each review appears as a session in the multi-session UI — click to switch between them.
|
|
126
|
+
When the global server is running, MCP tools automatically detect it and route reviews there instead of opening ephemeral browser tabs. Each review appears as a session in the multi-session UI — click to switch between them. Session status badges update live, and submitted sessions auto-expire after 5 minutes.
|
|
106
127
|
|
|
107
128
|
**Global setup** (optional, `diffprism server` runs this automatically):
|
|
108
129
|
|
|
109
130
|
```bash
|
|
110
131
|
# Configure skill + permissions globally (no git repo required)
|
|
111
132
|
diffprism setup --global
|
|
133
|
+
|
|
134
|
+
# Remove global configuration
|
|
135
|
+
diffprism teardown --global
|
|
112
136
|
```
|
|
113
137
|
|
|
114
138
|
Per-project MCP registration (`.mcp.json`) is still needed via `diffprism setup` in each project.
|
|
@@ -123,14 +147,14 @@ Opens a browser-based code review. Blocks until the engineer submits their decis
|
|
|
123
147
|
|
|
124
148
|
| Parameter | Required | Description |
|
|
125
149
|
|---------------|----------|-------------------------------------------------------------------|
|
|
126
|
-
| `diff_ref` | Yes | `"staged"`, `"unstaged"`, or a git ref range (e.g. `"HEAD~3..HEAD"`, `"main..feature"`) |
|
|
150
|
+
| `diff_ref` | Yes | `"staged"`, `"unstaged"`, `"working-copy"` (staged+unstaged grouped), or a git ref range (e.g. `"HEAD~3..HEAD"`, `"main..feature"`) |
|
|
127
151
|
| `title` | No | Title displayed in the review UI |
|
|
128
152
|
| `description` | No | Description of the changes |
|
|
129
153
|
| `reasoning` | No | Agent reasoning about why the changes were made (shown in the reasoning panel) |
|
|
130
154
|
|
|
131
155
|
### `update_review_context`
|
|
132
156
|
|
|
133
|
-
Pushes reasoning/context to a running
|
|
157
|
+
Pushes reasoning/context to a running DiffPrism session (watch mode or global server). Non-blocking — returns immediately.
|
|
134
158
|
|
|
135
159
|
| Parameter | Required | Description |
|
|
136
160
|
|---------------|----------|------------------------------------------------|
|
|
@@ -140,9 +164,12 @@ Pushes reasoning/context to a running `diffprism watch` session. Non-blocking
|
|
|
140
164
|
|
|
141
165
|
### `get_review_result`
|
|
142
166
|
|
|
143
|
-
Fetches the most recent review result from a
|
|
167
|
+
Fetches the most recent review result from a DiffPrism session (watch mode or global server). The result is marked as consumed after retrieval so it won't be returned again.
|
|
144
168
|
|
|
145
|
-
|
|
169
|
+
| Parameter | Required | Description |
|
|
170
|
+
|-----------|----------|-------------------------------------------------------------------|
|
|
171
|
+
| `wait` | No | If `true`, poll until a result is available (blocks up to timeout) |
|
|
172
|
+
| `timeout` | No | Max wait time in seconds when `wait=true` (default: 300, max: 600) |
|
|
146
173
|
|
|
147
174
|
**Returns (all tools):** A `ReviewResult` JSON object:
|
|
148
175
|
|
|
@@ -195,7 +222,7 @@ packages/git — Git diff extraction + unified diff parser
|
|
|
195
222
|
packages/analysis — Deterministic review briefing (complexity, test gaps, patterns)
|
|
196
223
|
packages/ui — React 19 + Vite 6 + Tailwind + Zustand diff viewer + session list
|
|
197
224
|
packages/mcp-server — MCP tool server, auto-routes to global server when available
|
|
198
|
-
cli/ — Commander CLI (review,
|
|
225
|
+
cli/ — Commander CLI (review, start, watch, setup, teardown, server commands)
|
|
199
226
|
```
|
|
200
227
|
|
|
201
228
|
### Requirements
|
|
@@ -207,4 +234,5 @@ cli/ — Commander CLI (review, serve, setup, server commands)
|
|
|
207
234
|
## Documentation
|
|
208
235
|
|
|
209
236
|
- [Claude Code / Claude Desktop Setup Guide](docs/claude-setup.md) — detailed MCP configuration, auto-approval, and troubleshooting
|
|
237
|
+
- [Workflows Guide](docs/workflows.md) — ephemeral, watch, and global server modes explained
|
|
210
238
|
- [UX Design Notes](docs/ux-design-notes.md) — design decisions, CLI defaults rationale, and multi-agent workflow thinking
|
package/dist/bin.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
startGlobalServer,
|
|
7
7
|
startReview,
|
|
8
8
|
startWatch
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-3IVV6O45.js";
|
|
10
10
|
|
|
11
11
|
// cli/src/index.ts
|
|
12
12
|
import { Command } from "commander";
|
|
@@ -832,7 +832,7 @@ async function serverStop() {
|
|
|
832
832
|
|
|
833
833
|
// cli/src/index.ts
|
|
834
834
|
var program = new Command();
|
|
835
|
-
program.name("diffprism").description("Local-first code review tool for agent-generated changes").version(true ? "0.
|
|
835
|
+
program.name("diffprism").description("Local-first code review tool for agent-generated changes").version(true ? "0.21.0" : "0.0.0-dev");
|
|
836
836
|
program.command("review [ref]").description("Open a browser-based diff review").option("--staged", "Review staged changes").option("--unstaged", "Review unstaged changes").option("-t, --title <title>", "Review title").option("--dev", "Use Vite dev server with HMR instead of static files").action(review);
|
|
837
837
|
program.command("start [ref]").description("Set up DiffPrism and start watching for changes").option("--staged", "Watch staged changes").option("--unstaged", "Watch unstaged changes").option("-t, --title <title>", "Review title").option("--interval <ms>", "Poll interval in milliseconds (default: 1000)").option("--dev", "Use Vite dev server with HMR instead of static files").option("--global", "Install skill globally (~/.claude/skills/)").option("--force", "Overwrite existing configuration files").action(start);
|
|
838
838
|
program.command("watch [ref]").description("Start a persistent diff watcher with live-updating browser UI").option("--staged", "Watch staged changes").option("--unstaged", "Watch unstaged changes").option("-t, --title <title>", "Review title").option("--interval <ms>", "Poll interval in milliseconds (default: 1000)").option("--dev", "Use Vite dev server with HMR instead of static files").action(watch);
|
|
@@ -1447,6 +1447,9 @@ import { randomUUID } from "crypto";
|
|
|
1447
1447
|
import getPort3 from "get-port";
|
|
1448
1448
|
import open3 from "open";
|
|
1449
1449
|
import { WebSocketServer as WebSocketServer3, WebSocket as WebSocket3 } from "ws";
|
|
1450
|
+
var SUBMITTED_TTL_MS = 5 * 60 * 1e3;
|
|
1451
|
+
var ABANDONED_TTL_MS = 60 * 60 * 1e3;
|
|
1452
|
+
var CLEANUP_INTERVAL_MS = 60 * 1e3;
|
|
1450
1453
|
var sessions2 = /* @__PURE__ */ new Map();
|
|
1451
1454
|
var clientSessions = /* @__PURE__ */ new Map();
|
|
1452
1455
|
var sessionWatchers = /* @__PURE__ */ new Map();
|
|
@@ -1470,6 +1473,7 @@ function toSummary(session) {
|
|
|
1470
1473
|
additions,
|
|
1471
1474
|
deletions,
|
|
1472
1475
|
status: session.status,
|
|
1476
|
+
decision: session.result?.decision,
|
|
1473
1477
|
createdAt: session.createdAt,
|
|
1474
1478
|
hasNewChanges: session.hasNewChanges
|
|
1475
1479
|
};
|
|
@@ -1522,6 +1526,23 @@ function sendToSessionClients(sessionId, msg) {
|
|
|
1522
1526
|
}
|
|
1523
1527
|
}
|
|
1524
1528
|
}
|
|
1529
|
+
function broadcastSessionUpdate(session) {
|
|
1530
|
+
broadcastToAll({
|
|
1531
|
+
type: "session:updated",
|
|
1532
|
+
payload: toSummary(session)
|
|
1533
|
+
});
|
|
1534
|
+
}
|
|
1535
|
+
function broadcastSessionRemoved(sessionId) {
|
|
1536
|
+
for (const [client, sid] of clientSessions.entries()) {
|
|
1537
|
+
if (sid === sessionId) {
|
|
1538
|
+
clientSessions.delete(client);
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
broadcastToAll({
|
|
1542
|
+
type: "session:removed",
|
|
1543
|
+
payload: { sessionId }
|
|
1544
|
+
});
|
|
1545
|
+
}
|
|
1525
1546
|
function hasViewersForSession(sessionId) {
|
|
1526
1547
|
for (const [client, sid] of clientSessions.entries()) {
|
|
1527
1548
|
if (sid === sessionId && client.readyState === WebSocket3.OPEN) {
|
|
@@ -1613,7 +1634,7 @@ async function handleApiRequest(req, res) {
|
|
|
1613
1634
|
const method = req.method ?? "GET";
|
|
1614
1635
|
const url = (req.url ?? "/").split("?")[0];
|
|
1615
1636
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
1616
|
-
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
1637
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
|
|
1617
1638
|
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
1618
1639
|
if (method === "OPTIONS") {
|
|
1619
1640
|
res.writeHead(204);
|
|
@@ -1695,6 +1716,7 @@ async function handleApiRequest(req, res) {
|
|
|
1695
1716
|
const result = JSON.parse(body);
|
|
1696
1717
|
session.result = result;
|
|
1697
1718
|
session.status = "submitted";
|
|
1719
|
+
broadcastSessionUpdate(session);
|
|
1698
1720
|
jsonResponse(res, 200, { ok: true });
|
|
1699
1721
|
} catch {
|
|
1700
1722
|
jsonResponse(res, 400, { error: "Invalid request body" });
|
|
@@ -1748,6 +1770,7 @@ async function handleApiRequest(req, res) {
|
|
|
1748
1770
|
if (deleteParams) {
|
|
1749
1771
|
stopSessionWatcher(deleteParams.id);
|
|
1750
1772
|
if (sessions2.delete(deleteParams.id)) {
|
|
1773
|
+
broadcastSessionRemoved(deleteParams.id);
|
|
1751
1774
|
jsonResponse(res, 200, { ok: true });
|
|
1752
1775
|
} else {
|
|
1753
1776
|
jsonResponse(res, 404, { error: "Session not found" });
|
|
@@ -1800,6 +1823,7 @@ async function startGlobalServer(options = {}) {
|
|
|
1800
1823
|
if (session) {
|
|
1801
1824
|
session.status = "in_review";
|
|
1802
1825
|
session.hasNewChanges = false;
|
|
1826
|
+
broadcastSessionUpdate(session);
|
|
1803
1827
|
const msg = {
|
|
1804
1828
|
type: "review:init",
|
|
1805
1829
|
payload: session.payload
|
|
@@ -1819,6 +1843,7 @@ async function startGlobalServer(options = {}) {
|
|
|
1819
1843
|
clientSessions.set(ws, session.id);
|
|
1820
1844
|
session.status = "in_review";
|
|
1821
1845
|
session.hasNewChanges = false;
|
|
1846
|
+
broadcastSessionUpdate(session);
|
|
1822
1847
|
ws.send(JSON.stringify({
|
|
1823
1848
|
type: "review:init",
|
|
1824
1849
|
payload: session.payload
|
|
@@ -1836,6 +1861,7 @@ async function startGlobalServer(options = {}) {
|
|
|
1836
1861
|
if (session) {
|
|
1837
1862
|
session.result = msg.payload;
|
|
1838
1863
|
session.status = "submitted";
|
|
1864
|
+
broadcastSessionUpdate(session);
|
|
1839
1865
|
}
|
|
1840
1866
|
}
|
|
1841
1867
|
} else if (msg.type === "session:select") {
|
|
@@ -1845,6 +1871,7 @@ async function startGlobalServer(options = {}) {
|
|
|
1845
1871
|
session.status = "in_review";
|
|
1846
1872
|
session.hasNewChanges = false;
|
|
1847
1873
|
startSessionWatcher(session.id);
|
|
1874
|
+
broadcastSessionUpdate(session);
|
|
1848
1875
|
ws.send(JSON.stringify({
|
|
1849
1876
|
type: "review:init",
|
|
1850
1877
|
payload: session.payload
|
|
@@ -1875,6 +1902,19 @@ async function startGlobalServer(options = {}) {
|
|
|
1875
1902
|
httpServer.on("error", reject);
|
|
1876
1903
|
httpServer.listen(httpPort, () => resolve());
|
|
1877
1904
|
});
|
|
1905
|
+
function cleanupExpiredSessions() {
|
|
1906
|
+
const now = Date.now();
|
|
1907
|
+
for (const [id, session] of sessions2.entries()) {
|
|
1908
|
+
const age = now - session.createdAt;
|
|
1909
|
+
const expired = session.status === "submitted" && age > SUBMITTED_TTL_MS || session.status === "pending" && age > ABANDONED_TTL_MS;
|
|
1910
|
+
if (expired) {
|
|
1911
|
+
stopSessionWatcher(id);
|
|
1912
|
+
sessions2.delete(id);
|
|
1913
|
+
broadcastSessionRemoved(id);
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
const cleanupTimer = setInterval(cleanupExpiredSessions, CLEANUP_INTERVAL_MS);
|
|
1878
1918
|
const serverInfo = {
|
|
1879
1919
|
httpPort,
|
|
1880
1920
|
wsPort,
|
|
@@ -1901,6 +1941,7 @@ Waiting for reviews...
|
|
|
1901
1941
|
}
|
|
1902
1942
|
};
|
|
1903
1943
|
async function stop() {
|
|
1944
|
+
clearInterval(cleanupTimer);
|
|
1904
1945
|
stopAllWatchers();
|
|
1905
1946
|
if (wss) {
|
|
1906
1947
|
for (const client of wss.clients) {
|
package/dist/mcp-server.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
readReviewResult,
|
|
8
8
|
readWatchFile,
|
|
9
9
|
startReview
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-3IVV6O45.js";
|
|
11
11
|
|
|
12
12
|
// packages/mcp-server/src/index.ts
|
|
13
13
|
import fs from "fs";
|
|
@@ -76,7 +76,7 @@ async function reviewViaGlobalServer(serverInfo, diffRef, options) {
|
|
|
76
76
|
async function startMcpServer() {
|
|
77
77
|
const server = new McpServer({
|
|
78
78
|
name: "diffprism",
|
|
79
|
-
version: true ? "0.
|
|
79
|
+
version: true ? "0.21.0" : "0.0.0-dev"
|
|
80
80
|
});
|
|
81
81
|
server.tool(
|
|
82
82
|
"open_review",
|
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{--diff-background-color:initial;--diff-text-color:initial;--diff-font-family:Consolas,Courier,monospace;--diff-selection-background-color:#b3d7ff;--diff-selection-text-color:var(--diff-text-color);--diff-gutter-insert-background-color:#d6fedb;--diff-gutter-insert-text-color:var(--diff-text-color);--diff-gutter-delete-background-color:#fadde0;--diff-gutter-delete-text-color:var(--diff-text-color);--diff-gutter-selected-background-color:#fffce0;--diff-gutter-selected-text-color:var(--diff-text-color);--diff-code-insert-background-color:#eaffee;--diff-code-insert-text-color:var(--diff-text-color);--diff-code-delete-background-color:#fdeff0;--diff-code-delete-text-color:var(--diff-text-color);--diff-code-insert-edit-background-color:#c0dc91;--diff-code-insert-edit-text-color:var(--diff-text-color);--diff-code-delete-edit-background-color:#f39ea2;--diff-code-delete-edit-text-color:var(--diff-text-color);--diff-code-selected-background-color:#fffce0;--diff-code-selected-text-color:var(--diff-text-color);--diff-omit-gutter-line-color:#cb2a1d}.diff{background-color:var(--diff-background-color);border-collapse:collapse;color:var(--diff-text-color);table-layout:fixed;width:100%}.diff::-moz-selection{background-color:#b3d7ff;background-color:var(--diff-selection-background-color);color:var(--diff-text-color);color:var(--diff-selection-text-color)}.diff::selection{background-color:#b3d7ff;background-color:var(--diff-selection-background-color);color:var(--diff-text-color);color:var(--diff-selection-text-color)}.diff td{padding-bottom:0;padding-top:0;vertical-align:top}.diff-line{font-family:Consolas,Courier,monospace;font-family:var(--diff-font-family);line-height:1.5}.diff-gutter>a{color:inherit;display:block}.diff-gutter{cursor:pointer;padding:0 1ch;text-align:right;-webkit-user-select:none;-moz-user-select:none;user-select:none}.diff-gutter-insert{background-color:#d6fedb;background-color:var(--diff-gutter-insert-background-color);color:var(--diff-text-color);color:var(--diff-gutter-insert-text-color)}.diff-gutter-delete{background-color:#fadde0;background-color:var(--diff-gutter-delete-background-color);color:var(--diff-text-color);color:var(--diff-gutter-delete-text-color)}.diff-gutter-omit{cursor:default}.diff-gutter-selected{background-color:#fffce0;background-color:var(--diff-gutter-selected-background-color);color:var(--diff-text-color);color:var(--diff-gutter-selected-text-color)}.diff-code{word-wrap:break-word;padding:0 0 0 .5em;white-space:pre-wrap;word-break:break-all}.diff-code-edit{color:inherit}.diff-code-insert{background-color:#eaffee;background-color:var(--diff-code-insert-background-color);color:var(--diff-text-color);color:var(--diff-code-insert-text-color)}.diff-code-insert .diff-code-edit{background-color:#c0dc91;background-color:var(--diff-code-insert-edit-background-color);color:var(--diff-text-color);color:var(--diff-code-insert-edit-text-color)}.diff-code-delete{background-color:#fdeff0;background-color:var(--diff-code-delete-background-color);color:var(--diff-text-color);color:var(--diff-code-delete-text-color)}.diff-code-delete .diff-code-edit{background-color:#f39ea2;background-color:var(--diff-code-delete-edit-background-color);color:var(--diff-text-color);color:var(--diff-code-delete-edit-text-color)}.diff-code-selected{background-color:#fffce0;background-color:var(--diff-code-selected-background-color);color:var(--diff-text-color);color:var(--diff-code-selected-text-color)}.diff-widget-content{vertical-align:top}.diff-gutter-col{width:7ch}.diff-gutter-omit{height:0}.diff-gutter-omit:before{background-color:#cb2a1d;background-color:var(--diff-omit-gutter-line-color);content:" ";display:block;height:100%;margin-left:4.6ch;overflow:hidden;white-space:pre;width:2px}.diff-decoration{line-height:1.5;-webkit-user-select:none;-moz-user-select:none;user-select:none}.diff-decoration-content{font-family:Consolas,Courier,monospace;font-family:var(--diff-font-family);padding:0}*,:before,:after{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / .5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / .5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}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;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{top:0;right:0;bottom:0;left:0}.right-2{right:.5rem}.top-2{top:.5rem}.z-50{z-index:50}.col-span-2{grid-column:span 2 / span 2}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-auto{margin-left:auto}.mr-1\.5{margin-right:.375rem}.mr-2{margin-right:.5rem}.mt-1{margin-top:.25rem}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.h-12{height:3rem}.h-16{height:4rem}.h-2{height:.5rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-6{height:1.5rem}.h-8{height:2rem}.h-full{height:100%}.h-screen{height:100vh}.min-h-0{min-height:0px}.w-12{width:3rem}.w-16{width:4rem}.w-2{width:.5rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-4{width:1rem}.w-6{width:1.5rem}.w-8{width:2rem}.w-\[280px\]{width:280px}.w-full{width:100%}.min-w-0{min-width:0px}.max-w-sm{max-width:24rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}@keyframes ping{75%,to{transform:scale(2);opacity:0}}.animate-ping{animation:ping 1s cubic-bezier(0,0,.2,1) infinite}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-x-6{-moz-column-gap:1.5rem;column-gap:1.5rem}.gap-y-3{row-gap:.75rem}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.overflow-auto{overflow:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-l-2{border-left-width:2px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-accent{border-color:var(--color-accent)}.border-blue-300{--tw-border-opacity:1;border-color:rgb(147 197 253 / var(--tw-border-opacity, 1))}.border-border{border-color:var(--color-border)}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219 / var(--tw-border-opacity, 1))}.border-green-300{--tw-border-opacity:1;border-color:rgb(134 239 172 / var(--tw-border-opacity, 1))}.border-green-500\/30{border-color:#22c55e4d}.border-orange-300{--tw-border-opacity:1;border-color:rgb(253 186 116 / var(--tw-border-opacity, 1))}.border-purple-300{--tw-border-opacity:1;border-color:rgb(216 180 254 / var(--tw-border-opacity, 1))}.border-red-300{--tw-border-opacity:1;border-color:rgb(252 165 165 / var(--tw-border-opacity, 1))}.border-red-500\/30{border-color:#ef44444d}.border-transparent{border-color:transparent}.border-yellow-300{--tw-border-opacity:1;border-color:rgb(253 224 71 / var(--tw-border-opacity, 1))}.border-yellow-500\/30{border-color:#eab3084d}.border-t-accent{border-top-color:var(--color-accent)}.bg-background{background-color:var(--color-background)}.bg-black\/50{background-color:#00000080}.bg-blue-100{--tw-bg-opacity:1;background-color:rgb(219 234 254 / var(--tw-bg-opacity, 1))}.bg-blue-400{--tw-bg-opacity:1;background-color:rgb(96 165 250 / var(--tw-bg-opacity, 1))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.bg-green-100{--tw-bg-opacity:1;background-color:rgb(220 252 231 / var(--tw-bg-opacity, 1))}.bg-green-400{--tw-bg-opacity:1;background-color:rgb(74 222 128 / var(--tw-bg-opacity, 1))}.bg-green-500{--tw-bg-opacity:1;background-color:rgb(34 197 94 / var(--tw-bg-opacity, 1))}.bg-green-600\/20{background-color:#16a34a33}.bg-orange-100{--tw-bg-opacity:1;background-color:rgb(255 237 213 / var(--tw-bg-opacity, 1))}.bg-purple-100{--tw-bg-opacity:1;background-color:rgb(243 232 255 / var(--tw-bg-opacity, 1))}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(254 226 226 / var(--tw-bg-opacity, 1))}.bg-red-600\/20{background-color:#dc262633}.bg-surface{background-color:var(--color-surface)}.bg-yellow-100{--tw-bg-opacity:1;background-color:rgb(254 249 195 / var(--tw-bg-opacity, 1))}.bg-yellow-600\/20{background-color:#ca8a0433}.p-0\.5{padding:.125rem}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.pb-3{padding-bottom:.75rem}.pr-6{padding-right:1.5rem}.pt-3{padding-top:.75rem}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-\[10px\]{font-size:10px}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.tracking-wide{letter-spacing:.025em}.text-accent{color:var(--color-accent)}.text-blue-700{--tw-text-opacity:1;color:rgb(29 78 216 / var(--tw-text-opacity, 1))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.text-green-400{--tw-text-opacity:1;color:rgb(74 222 128 / var(--tw-text-opacity, 1))}.text-green-700{--tw-text-opacity:1;color:rgb(21 128 61 / var(--tw-text-opacity, 1))}.text-orange-700{--tw-text-opacity:1;color:rgb(194 65 12 / var(--tw-text-opacity, 1))}.text-purple-700{--tw-text-opacity:1;color:rgb(126 34 206 / var(--tw-text-opacity, 1))}.text-red-400{--tw-text-opacity:1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28 / var(--tw-text-opacity, 1))}.text-text-primary{color:var(--color-text-primary)}.text-text-secondary{color:var(--color-text-secondary)}.text-yellow-400{--tw-text-opacity:1;color:rgb(250 204 21 / var(--tw-text-opacity, 1))}.text-yellow-700{--tw-text-opacity:1;color:rgb(161 98 7 / var(--tw-text-opacity, 1))}.opacity-0{opacity:0}.opacity-75{opacity:.75}.shadow-xl{--tw-shadow:0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-100{transition-duration:.1s}:root{--color-background: #ffffff;--color-surface: #f6f8fa;--color-border: #d0d7de;--color-text-primary: #1f2328;--color-text-secondary: #656d76;--color-accent: #0969da;--color-diff-bg: #ffffff;--color-diff-text: #1f2328;--color-gutter-bg: #f6f8fa;--color-gutter-text: #656d76;--color-gutter-border: #d0d7de;--color-diff-insert-bg: rgba(46, 160, 67, .15);--color-diff-insert-gutter-bg: rgba(46, 160, 67, .2);--color-diff-insert-gutter-text: #1a7f37;--color-diff-delete-bg: rgba(248, 81, 73, .15);--color-diff-delete-gutter-bg: rgba(248, 81, 73, .2);--color-diff-delete-gutter-text: #cf222e;--color-hunk-bg: rgba(9, 105, 218, .1);--color-hunk-border: #d0d7de;--color-hunk-gutter-bg: rgba(9, 105, 218, .15);--color-hunk-gutter-text: #0969da;--color-hunk-content-text: #656d76;--color-diff-edit-insert: rgba(46, 160, 67, .4);--color-diff-edit-delete: rgba(248, 81, 73, .4);--color-split-divider: #d0d7de;--color-widget-bg: #f6f8fa;--color-comment-btn-bg: #238636;--color-comment-indicator: #0969da;--color-scrollbar-track: #ffffff;--color-scrollbar-thumb: #d0d7de;--color-scrollbar-thumb-hover: #afb8c1;--color-token-comment: #6e7781;--color-token-punctuation: #1f2328;--color-token-property: #0550ae;--color-token-string: #0a3069;--color-token-operator: #cf222e;--color-token-keyword: #cf222e;--color-token-function: #8250df;--color-token-variable: #953800;--color-added: rgba(46, 160, 67, .44);--color-deleted: rgba(248, 81, 73, .44)}.dark{--color-background: #0d1117;--color-surface: #161b22;--color-border: #30363d;--color-text-primary: #e6edf3;--color-text-secondary: #8b949e;--color-accent: #58a6ff;--color-diff-bg: #0d1117;--color-diff-text: #e6edf3;--color-gutter-bg: #161b22;--color-gutter-text: #8b949e;--color-gutter-border: #30363d;--color-diff-insert-bg: rgba(46, 160, 67, .15);--color-diff-insert-gutter-bg: rgba(46, 160, 67, .2);--color-diff-insert-gutter-text: #7ee787;--color-diff-delete-bg: rgba(248, 81, 73, .15);--color-diff-delete-gutter-bg: rgba(248, 81, 73, .2);--color-diff-delete-gutter-text: #f85149;--color-hunk-bg: rgba(88, 166, 255, .1);--color-hunk-border: #30363d;--color-hunk-gutter-bg: rgba(88, 166, 255, .15);--color-hunk-gutter-text: #58a6ff;--color-hunk-content-text: #8b949e;--color-diff-edit-insert: rgba(46, 160, 67, .4);--color-diff-edit-delete: rgba(248, 81, 73, .4);--color-split-divider: #30363d;--color-widget-bg: #161b22;--color-comment-btn-bg: #238636;--color-comment-indicator: #58a6ff;--color-scrollbar-track: #0d1117;--color-scrollbar-thumb: #30363d;--color-scrollbar-thumb-hover: #484f58;--color-token-comment: #8b949e;--color-token-punctuation: #e6edf3;--color-token-property: #79c0ff;--color-token-string: #a5d6ff;--color-token-operator: #ff7b72;--color-token-keyword: #ff7b72;--color-token-function: #d2a8ff;--color-token-variable: #ffa657;--color-added: rgba(46, 160, 67, .44);--color-deleted: rgba(248, 81, 73, .44)}.diff-unified,.diff-split{background-color:var(--color-diff-bg);color:var(--color-diff-text);font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;font-size:13px;line-height:20px}.diff-unified .diff-gutter,.diff-split .diff-gutter{background-color:var(--color-gutter-bg);color:var(--color-gutter-text);border-right:1px solid var(--color-gutter-border);padding:0 8px;min-width:50px;text-align:right;-webkit-user-select:none;-moz-user-select:none;user-select:none;cursor:default}.diff-unified .diff-gutter-col,.diff-split .diff-gutter-col{width:60px;min-width:60px}.diff-unified .diff-code,.diff-split .diff-code{padding:0 12px;white-space:pre}.diff-unified .diff-code-insert,.diff-split .diff-code-insert{background-color:var(--color-diff-insert-bg)}.diff-unified .diff-code-insert .diff-code-text,.diff-split .diff-code-insert .diff-code-text{background-color:transparent}.diff-unified .diff-gutter-insert,.diff-split .diff-gutter-insert{background-color:var(--color-diff-insert-gutter-bg);color:var(--color-diff-insert-gutter-text)}.diff-unified .diff-code-delete,.diff-split .diff-code-delete{background-color:var(--color-diff-delete-bg)}.diff-unified .diff-code-delete .diff-code-text,.diff-split .diff-code-delete .diff-code-text{background-color:transparent}.diff-unified .diff-gutter-delete,.diff-split .diff-gutter-delete{background-color:var(--color-diff-delete-gutter-bg);color:var(--color-diff-delete-gutter-text)}.diff-unified .diff-code-normal,.diff-split .diff-code-normal{background-color:transparent}.diff-unified .diff-gutter-normal,.diff-split .diff-gutter-normal{background-color:var(--color-gutter-bg)}.diff-unified .diff-hunk-header,.diff-split .diff-hunk-header{background-color:var(--color-hunk-bg);border-top:1px solid var(--color-hunk-border);border-bottom:1px solid var(--color-hunk-border)}.diff-unified .diff-hunk-header-gutter,.diff-split .diff-hunk-header-gutter{background-color:var(--color-hunk-gutter-bg);color:var(--color-hunk-gutter-text)}.diff-unified .diff-hunk-header-content,.diff-split .diff-hunk-header-content{color:var(--color-hunk-content-text);padding:4px 12px;font-style:italic}.diff-unified .diff-code-edit .diff-code-text .diff-code-edit-text,.diff-split .diff-code-edit .diff-code-text .diff-code-edit-text{background-color:var(--color-diff-edit-insert);border-radius:2px}.diff-unified .diff-code-delete .diff-code-text .diff-code-edit-text,.diff-split .diff-code-delete .diff-code-text .diff-code-edit-text{background-color:var(--color-diff-edit-delete);border-radius:2px}.diff-unified table,.diff-split table{width:100%;border-collapse:collapse;table-layout:fixed}.diff-unified td,.diff-split td{vertical-align:top}.diff-split .diff-split-side-new .diff-gutter{border-left:1px solid var(--color-split-divider)}.diff-unified .token.comment,.diff-unified .token.prolog,.diff-unified .token.doctype,.diff-unified .token.cdata,.diff-split .token.comment,.diff-split .token.prolog,.diff-split .token.doctype,.diff-split .token.cdata{color:var(--color-token-comment)}.diff-unified .token.punctuation,.diff-split .token.punctuation{color:var(--color-token-punctuation)}.diff-unified .token.property,.diff-unified .token.tag,.diff-unified .token.boolean,.diff-unified .token.number,.diff-unified .token.constant,.diff-unified .token.symbol,.diff-split .token.property,.diff-split .token.tag,.diff-split .token.boolean,.diff-split .token.number,.diff-split .token.constant,.diff-split .token.symbol{color:var(--color-token-property)}.diff-unified .token.selector,.diff-unified .token.attr-name,.diff-unified .token.string,.diff-unified .token.char,.diff-unified .token.builtin,.diff-split .token.selector,.diff-split .token.attr-name,.diff-split .token.string,.diff-split .token.char,.diff-split .token.builtin{color:var(--color-token-string)}.diff-unified .token.operator,.diff-unified .token.entity,.diff-unified .token.url,.diff-split .token.operator,.diff-split .token.entity,.diff-split .token.url{color:var(--color-token-operator)}.diff-unified .token.atrule,.diff-unified .token.attr-value,.diff-unified .token.keyword,.diff-split .token.atrule,.diff-split .token.attr-value,.diff-split .token.keyword{color:var(--color-token-keyword)}.diff-unified .token.function,.diff-unified .token.class-name,.diff-split .token.function,.diff-split .token.class-name{color:var(--color-token-function)}.diff-unified .token.regex,.diff-unified .token.important,.diff-unified .token.variable,.diff-split .token.regex,.diff-split .token.important,.diff-split .token.variable{color:var(--color-token-variable)}.diff-unified .token.string,.diff-split .token.string{color:var(--color-token-string)}.diff-unified .diff-gutter,.diff-split .diff-gutter{cursor:pointer;position:relative}.diff-gutter-add-comment{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;border-radius:3px;background-color:var(--color-comment-btn-bg);color:#fff;font-size:12px;font-weight:700;line-height:1;position:absolute;left:2px;top:50%;transform:translateY(-50%)}.diff-comment-indicator{display:inline-block;width:6px;height:6px;border-radius:50%;background-color:var(--color-comment-indicator);position:absolute;left:4px;top:50%;transform:translateY(-50%)}.diff-widget{background-color:var(--color-widget-bg)}.diff-widget-content{padding:0}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:var(--color-scrollbar-track)}::-webkit-scrollbar-thumb{background:var(--color-scrollbar-thumb);border-radius:4px}::-webkit-scrollbar-thumb:hover{background:var(--color-scrollbar-thumb-hover)}.hover\:border-blue-400:hover{--tw-border-opacity:1;border-color:rgb(96 165 250 / var(--tw-border-opacity, 1))}.hover\:border-green-400:hover{--tw-border-opacity:1;border-color:rgb(74 222 128 / var(--tw-border-opacity, 1))}.hover\:border-red-400:hover{--tw-border-opacity:1;border-color:rgb(248 113 113 / var(--tw-border-opacity, 1))}.hover\:bg-blue-200:hover{--tw-bg-opacity:1;background-color:rgb(191 219 254 / var(--tw-bg-opacity, 1))}.hover\:bg-green-200:hover{--tw-bg-opacity:1;background-color:rgb(187 247 208 / var(--tw-bg-opacity, 1))}.hover\:bg-red-200:hover{--tw-bg-opacity:1;background-color:rgb(254 202 202 / var(--tw-bg-opacity, 1))}.hover\:text-accent:hover{color:var(--color-accent)}.hover\:text-red-700:hover{--tw-text-opacity:1;color:rgb(185 28 28 / var(--tw-text-opacity, 1))}.hover\:text-text-primary:hover{color:var(--color-text-primary)}.focus\:border-accent:focus{border-color:var(--color-accent)}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-1:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-accent:focus{--tw-ring-color:var(--color-accent)}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-40:disabled{opacity:.4}.group:hover .group-hover\:text-text-primary{color:var(--color-text-primary)}.group\/comment:hover .group-hover\/comment\:opacity-100{opacity:1}.group:hover .group-hover\:opacity-40{opacity:.4}.dark\:border-blue-500\/30:is(.dark *){border-color:#3b82f64d}.dark\:border-gray-500\/30:is(.dark *){border-color:#6b72804d}.dark\:border-green-500\/30:is(.dark *){border-color:#22c55e4d}.dark\:border-orange-500\/30:is(.dark *){border-color:#f973164d}.dark\:border-purple-500\/30:is(.dark *){border-color:#a855f74d}.dark\:border-red-500\/30:is(.dark *){border-color:#ef44444d}.dark\:border-yellow-500\/30:is(.dark *){border-color:#eab3084d}.dark\:bg-blue-600\/20:is(.dark *){background-color:#2563eb33}.dark\:bg-gray-600\/20:is(.dark *){background-color:#4b556333}.dark\:bg-green-600\/20:is(.dark *){background-color:#16a34a33}.dark\:bg-orange-600\/20:is(.dark *){background-color:#ea580c33}.dark\:bg-purple-600\/20:is(.dark *){background-color:#9333ea33}.dark\:bg-red-600\/20:is(.dark *){background-color:#dc262633}.dark\:bg-yellow-600\/20:is(.dark *){background-color:#ca8a0433}.dark\:text-blue-400:is(.dark *){--tw-text-opacity:1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.dark\:text-gray-400:is(.dark *){--tw-text-opacity:1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.dark\:text-green-400:is(.dark *){--tw-text-opacity:1;color:rgb(74 222 128 / var(--tw-text-opacity, 1))}.dark\:text-orange-400:is(.dark *){--tw-text-opacity:1;color:rgb(251 146 60 / var(--tw-text-opacity, 1))}.dark\:text-purple-400:is(.dark *){--tw-text-opacity:1;color:rgb(192 132 252 / var(--tw-text-opacity, 1))}.dark\:text-red-400:is(.dark *){--tw-text-opacity:1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.dark\:text-yellow-400:is(.dark *){--tw-text-opacity:1;color:rgb(250 204 21 / var(--tw-text-opacity, 1))}.dark\:hover\:border-blue-500\/50:hover:is(.dark *){border-color:#3b82f680}.dark\:hover\:border-green-500\/50:hover:is(.dark *){border-color:#22c55e80}.dark\:hover\:border-red-500\/50:hover:is(.dark *){border-color:#ef444480}.dark\:hover\:bg-blue-600\/30:hover:is(.dark *){background-color:#2563eb4d}.dark\:hover\:bg-green-600\/30:hover:is(.dark *){background-color:#16a34a4d}.dark\:hover\:bg-red-600\/30:hover:is(.dark *){background-color:#dc26264d}.dark\:hover\:text-red-400:hover:is(.dark *){--tw-text-opacity:1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}
|