diffprism 0.20.0 → 0.20.2
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/dist/bin.js +17 -9
- package/dist/{chunk-4VXA6GCO.js → chunk-3CQCLFF3.js} +136 -13
- package/dist/mcp-server.js +3 -3
- package/package.json +1 -1
- package/ui-dist/assets/index-7eOJS8DL.css +1 -0
- package/ui-dist/assets/{index-BfIxxwO-.js → index-DTAddKrQ.js} +69 -64
- package/ui-dist/index.html +2 -2
- package/ui-dist/assets/index-BcuyMNeU.css +0 -1
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-3CQCLFF3.js";
|
|
10
10
|
|
|
11
11
|
// cli/src/index.ts
|
|
12
12
|
import { Command } from "commander";
|
|
@@ -144,6 +144,12 @@ You can also check for feedback without blocking by calling \`get_review_result\
|
|
|
144
144
|
`;
|
|
145
145
|
|
|
146
146
|
// cli/src/commands/setup.ts
|
|
147
|
+
var GITIGNORE_ENTRIES = [
|
|
148
|
+
".diffprism",
|
|
149
|
+
".mcp.json",
|
|
150
|
+
".claude/settings.json",
|
|
151
|
+
".claude/skills/review/"
|
|
152
|
+
];
|
|
147
153
|
function findGitRoot(from) {
|
|
148
154
|
let dir = path.resolve(from);
|
|
149
155
|
while (true) {
|
|
@@ -306,27 +312,28 @@ async function promptUser(question) {
|
|
|
306
312
|
}
|
|
307
313
|
async function setupGitignore(gitRoot) {
|
|
308
314
|
const filePath = path.join(gitRoot, ".gitignore");
|
|
309
|
-
const entry = ".diffprism";
|
|
310
315
|
if (fs.existsSync(filePath)) {
|
|
311
316
|
const content = fs.readFileSync(filePath, "utf-8");
|
|
312
317
|
const lines = content.split("\n").map((l) => l.trim());
|
|
313
|
-
|
|
318
|
+
const missing = GITIGNORE_ENTRIES.filter((e) => !lines.includes(e));
|
|
319
|
+
if (missing.length === 0) {
|
|
314
320
|
return { action: "skipped", filePath };
|
|
315
321
|
}
|
|
316
|
-
const
|
|
322
|
+
const suffix = missing.map((e) => e + "\n").join("");
|
|
323
|
+
const newContent = content.endsWith("\n") ? content + suffix : content + "\n" + suffix;
|
|
317
324
|
fs.writeFileSync(filePath, newContent);
|
|
318
325
|
return { action: "updated", filePath };
|
|
319
326
|
}
|
|
320
327
|
const confirmed = await promptUser(
|
|
321
|
-
"No .gitignore found. Create one with
|
|
328
|
+
"No .gitignore found. Create one with DiffPrism entries? (Y/n) "
|
|
322
329
|
);
|
|
323
330
|
if (!confirmed) {
|
|
324
331
|
console.log(
|
|
325
|
-
" Warning:
|
|
332
|
+
" Warning: DiffPrism files will appear in git status and may be accidentally committed."
|
|
326
333
|
);
|
|
327
334
|
return { action: "skipped", filePath };
|
|
328
335
|
}
|
|
329
|
-
fs.writeFileSync(filePath,
|
|
336
|
+
fs.writeFileSync(filePath, GITIGNORE_ENTRIES.map((e) => e + "\n").join(""));
|
|
330
337
|
return { action: "created", filePath };
|
|
331
338
|
}
|
|
332
339
|
async function setup(flags) {
|
|
@@ -534,7 +541,8 @@ function teardownGitignore(gitRoot) {
|
|
|
534
541
|
}
|
|
535
542
|
const content = fs2.readFileSync(filePath, "utf-8");
|
|
536
543
|
const lines = content.split("\n");
|
|
537
|
-
const
|
|
544
|
+
const entrySet = new Set(GITIGNORE_ENTRIES);
|
|
545
|
+
const filtered = lines.filter((l) => !entrySet.has(l.trim()));
|
|
538
546
|
if (filtered.length === lines.length) {
|
|
539
547
|
return { action: "skipped", filePath };
|
|
540
548
|
}
|
|
@@ -824,7 +832,7 @@ async function serverStop() {
|
|
|
824
832
|
|
|
825
833
|
// cli/src/index.ts
|
|
826
834
|
var program = new Command();
|
|
827
|
-
program.name("diffprism").description("Local-first code review tool for agent-generated changes").version(true ? "0.20.
|
|
835
|
+
program.name("diffprism").description("Local-first code review tool for agent-generated changes").version(true ? "0.20.2" : "0.0.0-dev");
|
|
828
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);
|
|
829
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);
|
|
830
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);
|
|
@@ -1132,7 +1132,6 @@ async function isServerAlive() {
|
|
|
1132
1132
|
}
|
|
1133
1133
|
|
|
1134
1134
|
// packages/core/src/watch.ts
|
|
1135
|
-
import { createHash } from "crypto";
|
|
1136
1135
|
import getPort2 from "get-port";
|
|
1137
1136
|
import open2 from "open";
|
|
1138
1137
|
|
|
@@ -1265,7 +1264,8 @@ function createWatchBridge(port, callbacks) {
|
|
|
1265
1264
|
});
|
|
1266
1265
|
}
|
|
1267
1266
|
|
|
1268
|
-
// packages/core/src/
|
|
1267
|
+
// packages/core/src/diff-utils.ts
|
|
1268
|
+
import { createHash } from "crypto";
|
|
1269
1269
|
function hashDiff(rawDiff) {
|
|
1270
1270
|
return createHash("sha256").update(rawDiff).digest("hex");
|
|
1271
1271
|
}
|
|
@@ -1296,6 +1296,8 @@ function detectChangedFiles(oldDiffSet, newDiffSet) {
|
|
|
1296
1296
|
}
|
|
1297
1297
|
return changed;
|
|
1298
1298
|
}
|
|
1299
|
+
|
|
1300
|
+
// packages/core/src/watch.ts
|
|
1299
1301
|
async function startWatch(options) {
|
|
1300
1302
|
const {
|
|
1301
1303
|
diffRef,
|
|
@@ -1447,6 +1449,8 @@ import open3 from "open";
|
|
|
1447
1449
|
import { WebSocketServer as WebSocketServer3, WebSocket as WebSocket3 } from "ws";
|
|
1448
1450
|
var sessions2 = /* @__PURE__ */ new Map();
|
|
1449
1451
|
var clientSessions = /* @__PURE__ */ new Map();
|
|
1452
|
+
var sessionWatchers = /* @__PURE__ */ new Map();
|
|
1453
|
+
var serverPollInterval = 2e3;
|
|
1450
1454
|
var reopenBrowserIfNeeded = null;
|
|
1451
1455
|
function toSummary(session) {
|
|
1452
1456
|
const { payload } = session;
|
|
@@ -1466,7 +1470,9 @@ function toSummary(session) {
|
|
|
1466
1470
|
additions,
|
|
1467
1471
|
deletions,
|
|
1468
1472
|
status: session.status,
|
|
1469
|
-
|
|
1473
|
+
decision: session.result?.decision,
|
|
1474
|
+
createdAt: session.createdAt,
|
|
1475
|
+
hasNewChanges: session.hasNewChanges
|
|
1470
1476
|
};
|
|
1471
1477
|
}
|
|
1472
1478
|
function readBody(req) {
|
|
@@ -1517,6 +1523,93 @@ function sendToSessionClients(sessionId, msg) {
|
|
|
1517
1523
|
}
|
|
1518
1524
|
}
|
|
1519
1525
|
}
|
|
1526
|
+
function hasViewersForSession(sessionId) {
|
|
1527
|
+
for (const [client, sid] of clientSessions.entries()) {
|
|
1528
|
+
if (sid === sessionId && client.readyState === WebSocket3.OPEN) {
|
|
1529
|
+
return true;
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
return false;
|
|
1533
|
+
}
|
|
1534
|
+
function startSessionWatcher(sessionId) {
|
|
1535
|
+
if (sessionWatchers.has(sessionId)) return;
|
|
1536
|
+
const session = sessions2.get(sessionId);
|
|
1537
|
+
if (!session?.diffRef) return;
|
|
1538
|
+
const interval = setInterval(() => {
|
|
1539
|
+
const s = sessions2.get(sessionId);
|
|
1540
|
+
if (!s?.diffRef) {
|
|
1541
|
+
stopSessionWatcher(sessionId);
|
|
1542
|
+
return;
|
|
1543
|
+
}
|
|
1544
|
+
try {
|
|
1545
|
+
const { diffSet: newDiffSet, rawDiff: newRawDiff } = getDiff(s.diffRef, {
|
|
1546
|
+
cwd: s.projectPath
|
|
1547
|
+
});
|
|
1548
|
+
const newHash = hashDiff(newRawDiff);
|
|
1549
|
+
if (newHash !== s.lastDiffHash) {
|
|
1550
|
+
const newBriefing = analyze(newDiffSet);
|
|
1551
|
+
const changedFiles = detectChangedFiles(s.lastDiffSet ?? null, newDiffSet);
|
|
1552
|
+
s.payload = {
|
|
1553
|
+
...s.payload,
|
|
1554
|
+
diffSet: newDiffSet,
|
|
1555
|
+
rawDiff: newRawDiff,
|
|
1556
|
+
briefing: newBriefing
|
|
1557
|
+
};
|
|
1558
|
+
s.lastDiffHash = newHash;
|
|
1559
|
+
s.lastDiffSet = newDiffSet;
|
|
1560
|
+
if (hasViewersForSession(sessionId)) {
|
|
1561
|
+
sendToSessionClients(sessionId, {
|
|
1562
|
+
type: "diff:update",
|
|
1563
|
+
payload: {
|
|
1564
|
+
diffSet: newDiffSet,
|
|
1565
|
+
rawDiff: newRawDiff,
|
|
1566
|
+
briefing: newBriefing,
|
|
1567
|
+
changedFiles,
|
|
1568
|
+
timestamp: Date.now()
|
|
1569
|
+
}
|
|
1570
|
+
});
|
|
1571
|
+
s.hasNewChanges = false;
|
|
1572
|
+
} else {
|
|
1573
|
+
s.hasNewChanges = true;
|
|
1574
|
+
broadcastSessionList();
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
} catch {
|
|
1578
|
+
}
|
|
1579
|
+
}, serverPollInterval);
|
|
1580
|
+
sessionWatchers.set(sessionId, interval);
|
|
1581
|
+
}
|
|
1582
|
+
function stopSessionWatcher(sessionId) {
|
|
1583
|
+
const interval = sessionWatchers.get(sessionId);
|
|
1584
|
+
if (interval) {
|
|
1585
|
+
clearInterval(interval);
|
|
1586
|
+
sessionWatchers.delete(sessionId);
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
function startAllWatchers() {
|
|
1590
|
+
for (const [id, session] of sessions2.entries()) {
|
|
1591
|
+
if (session.diffRef && !sessionWatchers.has(id)) {
|
|
1592
|
+
startSessionWatcher(id);
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
function stopAllWatchers() {
|
|
1597
|
+
for (const [id, interval] of sessionWatchers.entries()) {
|
|
1598
|
+
clearInterval(interval);
|
|
1599
|
+
}
|
|
1600
|
+
sessionWatchers.clear();
|
|
1601
|
+
}
|
|
1602
|
+
function hasConnectedClients() {
|
|
1603
|
+
if (!wss) return false;
|
|
1604
|
+
for (const client of wss.clients) {
|
|
1605
|
+
if (client.readyState === WebSocket3.OPEN) return true;
|
|
1606
|
+
}
|
|
1607
|
+
return false;
|
|
1608
|
+
}
|
|
1609
|
+
function broadcastSessionList() {
|
|
1610
|
+
const summaries = Array.from(sessions2.values()).map(toSummary);
|
|
1611
|
+
broadcastToAll({ type: "session:list", payload: summaries });
|
|
1612
|
+
}
|
|
1520
1613
|
async function handleApiRequest(req, res) {
|
|
1521
1614
|
const method = req.method ?? "GET";
|
|
1522
1615
|
const url = (req.url ?? "/").split("?")[0];
|
|
@@ -1543,18 +1636,28 @@ async function handleApiRequest(req, res) {
|
|
|
1543
1636
|
if (method === "POST" && url === "/api/reviews") {
|
|
1544
1637
|
try {
|
|
1545
1638
|
const body = await readBody(req);
|
|
1546
|
-
const { payload, projectPath } = JSON.parse(body);
|
|
1639
|
+
const { payload, projectPath, diffRef } = JSON.parse(body);
|
|
1547
1640
|
const sessionId = `session-${randomUUID().slice(0, 8)}`;
|
|
1548
1641
|
payload.reviewId = sessionId;
|
|
1642
|
+
if (diffRef) {
|
|
1643
|
+
payload.watchMode = true;
|
|
1644
|
+
}
|
|
1549
1645
|
const session = {
|
|
1550
1646
|
id: sessionId,
|
|
1551
1647
|
payload,
|
|
1552
1648
|
projectPath,
|
|
1553
1649
|
status: "pending",
|
|
1554
1650
|
createdAt: Date.now(),
|
|
1555
|
-
result: null
|
|
1651
|
+
result: null,
|
|
1652
|
+
diffRef,
|
|
1653
|
+
lastDiffHash: diffRef ? hashDiff(payload.rawDiff) : void 0,
|
|
1654
|
+
lastDiffSet: diffRef ? payload.diffSet : void 0,
|
|
1655
|
+
hasNewChanges: false
|
|
1556
1656
|
};
|
|
1557
1657
|
sessions2.set(sessionId, session);
|
|
1658
|
+
if (diffRef && hasConnectedClients()) {
|
|
1659
|
+
startSessionWatcher(sessionId);
|
|
1660
|
+
}
|
|
1558
1661
|
broadcastToAll({
|
|
1559
1662
|
type: "session:added",
|
|
1560
1663
|
payload: toSummary(session)
|
|
@@ -1593,6 +1696,7 @@ async function handleApiRequest(req, res) {
|
|
|
1593
1696
|
const result = JSON.parse(body);
|
|
1594
1697
|
session.result = result;
|
|
1595
1698
|
session.status = "submitted";
|
|
1699
|
+
broadcastToAll({ type: "session:updated", payload: toSummary(session) });
|
|
1596
1700
|
jsonResponse(res, 200, { ok: true });
|
|
1597
1701
|
} catch {
|
|
1598
1702
|
jsonResponse(res, 400, { error: "Invalid request body" });
|
|
@@ -1644,6 +1748,7 @@ async function handleApiRequest(req, res) {
|
|
|
1644
1748
|
}
|
|
1645
1749
|
const deleteParams = matchRoute(method, url, "DELETE", "/api/reviews/:id");
|
|
1646
1750
|
if (deleteParams) {
|
|
1751
|
+
stopSessionWatcher(deleteParams.id);
|
|
1647
1752
|
if (sessions2.delete(deleteParams.id)) {
|
|
1648
1753
|
jsonResponse(res, 200, { ok: true });
|
|
1649
1754
|
} else {
|
|
@@ -1659,8 +1764,10 @@ async function startGlobalServer(options = {}) {
|
|
|
1659
1764
|
httpPort: preferredHttpPort = 24680,
|
|
1660
1765
|
wsPort: preferredWsPort = 24681,
|
|
1661
1766
|
silent = false,
|
|
1662
|
-
dev = false
|
|
1767
|
+
dev = false,
|
|
1768
|
+
pollInterval = 2e3
|
|
1663
1769
|
} = options;
|
|
1770
|
+
serverPollInterval = pollInterval;
|
|
1664
1771
|
const [httpPort, wsPort] = await Promise.all([
|
|
1665
1772
|
getPort3({ port: preferredHttpPort }),
|
|
1666
1773
|
getPort3({ port: preferredWsPort })
|
|
@@ -1686,6 +1793,7 @@ async function startGlobalServer(options = {}) {
|
|
|
1686
1793
|
});
|
|
1687
1794
|
wss = new WebSocketServer3({ port: wsPort });
|
|
1688
1795
|
wss.on("connection", (ws, req) => {
|
|
1796
|
+
startAllWatchers();
|
|
1689
1797
|
const url = new URL(req.url ?? "/", `http://localhost:${wsPort}`);
|
|
1690
1798
|
const sessionId = url.searchParams.get("sessionId");
|
|
1691
1799
|
if (sessionId) {
|
|
@@ -1693,6 +1801,8 @@ async function startGlobalServer(options = {}) {
|
|
|
1693
1801
|
const session = sessions2.get(sessionId);
|
|
1694
1802
|
if (session) {
|
|
1695
1803
|
session.status = "in_review";
|
|
1804
|
+
session.hasNewChanges = false;
|
|
1805
|
+
broadcastToAll({ type: "session:updated", payload: toSummary(session) });
|
|
1696
1806
|
const msg = {
|
|
1697
1807
|
type: "review:init",
|
|
1698
1808
|
payload: session.payload
|
|
@@ -1711,6 +1821,8 @@ async function startGlobalServer(options = {}) {
|
|
|
1711
1821
|
if (session) {
|
|
1712
1822
|
clientSessions.set(ws, session.id);
|
|
1713
1823
|
session.status = "in_review";
|
|
1824
|
+
session.hasNewChanges = false;
|
|
1825
|
+
broadcastToAll({ type: "session:updated", payload: toSummary(session) });
|
|
1714
1826
|
ws.send(JSON.stringify({
|
|
1715
1827
|
type: "review:init",
|
|
1716
1828
|
payload: session.payload
|
|
@@ -1728,6 +1840,7 @@ async function startGlobalServer(options = {}) {
|
|
|
1728
1840
|
if (session) {
|
|
1729
1841
|
session.result = msg.payload;
|
|
1730
1842
|
session.status = "submitted";
|
|
1843
|
+
broadcastToAll({ type: "session:updated", payload: toSummary(session) });
|
|
1731
1844
|
}
|
|
1732
1845
|
}
|
|
1733
1846
|
} else if (msg.type === "session:select") {
|
|
@@ -1735,17 +1848,33 @@ async function startGlobalServer(options = {}) {
|
|
|
1735
1848
|
if (session) {
|
|
1736
1849
|
clientSessions.set(ws, session.id);
|
|
1737
1850
|
session.status = "in_review";
|
|
1851
|
+
session.hasNewChanges = false;
|
|
1852
|
+
startSessionWatcher(session.id);
|
|
1853
|
+
broadcastToAll({ type: "session:updated", payload: toSummary(session) });
|
|
1738
1854
|
ws.send(JSON.stringify({
|
|
1739
1855
|
type: "review:init",
|
|
1740
1856
|
payload: session.payload
|
|
1741
1857
|
}));
|
|
1742
1858
|
}
|
|
1859
|
+
} else if (msg.type === "session:close") {
|
|
1860
|
+
const closedId = msg.payload.sessionId;
|
|
1861
|
+
stopSessionWatcher(closedId);
|
|
1862
|
+
sessions2.delete(closedId);
|
|
1863
|
+
for (const [client, sid] of clientSessions.entries()) {
|
|
1864
|
+
if (sid === closedId) {
|
|
1865
|
+
clientSessions.delete(client);
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
broadcastSessionList();
|
|
1743
1869
|
}
|
|
1744
1870
|
} catch {
|
|
1745
1871
|
}
|
|
1746
1872
|
});
|
|
1747
1873
|
ws.on("close", () => {
|
|
1748
1874
|
clientSessions.delete(ws);
|
|
1875
|
+
if (!hasConnectedClients()) {
|
|
1876
|
+
stopAllWatchers();
|
|
1877
|
+
}
|
|
1749
1878
|
});
|
|
1750
1879
|
});
|
|
1751
1880
|
await new Promise((resolve, reject) => {
|
|
@@ -1772,19 +1901,13 @@ Waiting for reviews...
|
|
|
1772
1901
|
}
|
|
1773
1902
|
const uiUrl = `http://localhost:${uiPort}?wsPort=${wsPort}&serverMode=true`;
|
|
1774
1903
|
await open3(uiUrl);
|
|
1775
|
-
function hasConnectedClients() {
|
|
1776
|
-
if (!wss) return false;
|
|
1777
|
-
for (const client of wss.clients) {
|
|
1778
|
-
if (client.readyState === WebSocket3.OPEN) return true;
|
|
1779
|
-
}
|
|
1780
|
-
return false;
|
|
1781
|
-
}
|
|
1782
1904
|
reopenBrowserIfNeeded = () => {
|
|
1783
1905
|
if (!hasConnectedClients()) {
|
|
1784
1906
|
open3(uiUrl);
|
|
1785
1907
|
}
|
|
1786
1908
|
};
|
|
1787
1909
|
async function stop() {
|
|
1910
|
+
stopAllWatchers();
|
|
1788
1911
|
if (wss) {
|
|
1789
1912
|
for (const client of wss.clients) {
|
|
1790
1913
|
client.close();
|
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-3CQCLFF3.js";
|
|
11
11
|
|
|
12
12
|
// packages/mcp-server/src/index.ts
|
|
13
13
|
import fs from "fs";
|
|
@@ -47,7 +47,7 @@ async function reviewViaGlobalServer(serverInfo, diffRef, options) {
|
|
|
47
47
|
{
|
|
48
48
|
method: "POST",
|
|
49
49
|
headers: { "Content-Type": "application/json" },
|
|
50
|
-
body: JSON.stringify({ payload, projectPath: cwd })
|
|
50
|
+
body: JSON.stringify({ payload, projectPath: cwd, diffRef })
|
|
51
51
|
}
|
|
52
52
|
);
|
|
53
53
|
if (!createResponse.ok) {
|
|
@@ -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.20.
|
|
79
|
+
version: true ? "0.20.2" : "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))}
|