linkshell-cli 0.5.30 → 0.5.31
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/cli/src/runtime/acp/agent-workspace.d.ts +10 -0
- package/dist/cli/src/runtime/acp/agent-workspace.js +212 -6
- package/dist/cli/src/runtime/acp/agent-workspace.js.map +1 -1
- package/dist/cli/src/runtime/acp/claude-sdk-client.d.ts +16 -0
- package/dist/cli/src/runtime/acp/claude-sdk-client.js +161 -30
- package/dist/cli/src/runtime/acp/claude-sdk-client.js.map +1 -1
- package/dist/cli/src/runtime/acp/claude-stream-json-client.d.ts +1 -0
- package/dist/cli/src/runtime/acp/claude-stream-json-client.js +44 -19
- package/dist/cli/src/runtime/acp/claude-stream-json-client.js.map +1 -1
- package/dist/cli/tsconfig.tsbuildinfo +1 -1
- package/dist/shared-protocol/src/index.d.ts +321 -0
- package/dist/shared-protocol/src/index.js +22 -0
- package/dist/shared-protocol/src/index.js.map +1 -1
- package/package.json +3 -3
- package/src/runtime/acp/agent-workspace.ts +216 -5
- package/src/runtime/acp/claude-sdk-client.ts +161 -29
- package/src/runtime/acp/claude-stream-json-client.ts +42 -19
- package/web/assets/index-D1fHT3_5.css +33 -0
- package/web/assets/{index-DABStn7S.js → index-DFdIi7vi.js} +44 -44
- package/web/index.html +2 -2
- package/web/assets/index-CRyJIhW8.css +0 -33
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { homedir } from "node:os";
|
|
2
|
-
import { readdirSync, existsSync, readFileSync, statSync } from "node:fs";
|
|
2
|
+
import { readdirSync, existsSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
3
4
|
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
4
5
|
import type { AgentFraming, AgentProtocol } from "./provider-resolver.js";
|
|
5
6
|
|
|
@@ -403,16 +404,15 @@ export function parseClaudeJsonlSession(input: {
|
|
|
403
404
|
* stale, the driver is gone → idle.
|
|
404
405
|
* Verified against real transcripts: mid-turn+fresh→running, mid-turn+stale→
|
|
405
406
|
* idle, end_turn+fresh→idle, half-written-line+fresh→running. */
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
// possibly-huge transcript just to read its tail.
|
|
407
|
+
const TRANSCRIPT_FRESH_MS = 10_000;
|
|
408
|
+
|
|
409
|
+
/** The structural half of the status verdict: does the LAST record of a
|
|
410
|
+
* transcript indicate an in-progress turn (awaiting/producing an assistant
|
|
411
|
+
* response, or a half-written trailing line)? This is purely content-derived
|
|
412
|
+
* — it does NOT depend on the clock — so it can be cached alongside the parsed
|
|
413
|
+
* metadata and reused across syncs until the file's (mtime,size) changes.
|
|
414
|
+
* Scans backward from the end to avoid split()-ing a possibly-huge transcript. */
|
|
415
|
+
function deriveTranscriptMidTurn(text: string): boolean {
|
|
416
416
|
let last: Record<string, unknown> | undefined;
|
|
417
417
|
let sawUnparseableTail = false;
|
|
418
418
|
let end = text.length;
|
|
@@ -429,44 +429,76 @@ function deriveTranscriptStatus(text: string, mtimeMs: number, nowMs: number): "
|
|
|
429
429
|
sawUnparseableTail = true;
|
|
430
430
|
}
|
|
431
431
|
}
|
|
432
|
-
if (!last) return
|
|
432
|
+
if (!last) return false;
|
|
433
433
|
const message = asRecord(last.message);
|
|
434
434
|
const role = stringField(message, ["role"]) ?? stringField(last, ["type"]);
|
|
435
435
|
const stop = message ? message.stop_reason ?? null : null;
|
|
436
|
-
if (role === "assistant" && stop === "end_turn") return
|
|
437
|
-
|
|
436
|
+
if (role === "assistant" && stop === "end_turn") return false;
|
|
437
|
+
return (
|
|
438
438
|
role === "user" ||
|
|
439
439
|
last.type === "user" ||
|
|
440
440
|
(role === "assistant" && (stop === "tool_use" || stop === null)) ||
|
|
441
|
-
sawUnparseableTail
|
|
442
|
-
|
|
441
|
+
sawUnparseableTail
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/** Combine the (clock-independent) structural verdict with the freshness signal.
|
|
446
|
+
* A stale file (no writes within FRESH_MS) is always idle; a mid-turn file that
|
|
447
|
+
* is still being appended to is running. Cheap: one comparison + one boolean. */
|
|
448
|
+
function statusFromMidTurn(midTurn: boolean, mtimeMs: number, nowMs: number): "running" | "idle" {
|
|
449
|
+
if (nowMs - mtimeMs >= TRANSCRIPT_FRESH_MS) return "idle";
|
|
443
450
|
return midTurn ? "running" : "idle";
|
|
444
451
|
}
|
|
445
452
|
|
|
446
|
-
|
|
447
|
-
|
|
453
|
+
/** Derive whether an on-disk Claude transcript is being actively driven RIGHT
|
|
454
|
+
* NOW, purely from the file. See {@link deriveTranscriptMidTurn} /
|
|
455
|
+
* {@link statusFromMidTurn}; kept as a convenience wrapper for callers that
|
|
456
|
+
* hold the full text and the clock but no cache. */
|
|
457
|
+
function deriveTranscriptStatus(text: string, mtimeMs: number, nowMs: number): "running" | "idle" {
|
|
458
|
+
// Stale short-circuit: most sessions in ~/.claude/projects are old, so avoid
|
|
459
|
+
// the backward scan entirely when the file can't possibly be running.
|
|
460
|
+
if (nowMs - mtimeMs >= TRANSCRIPT_FRESH_MS) return "idle";
|
|
461
|
+
return statusFromMidTurn(deriveTranscriptMidTurn(text), mtimeMs, nowMs);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/** Parse a transcript into the clock-independent, cacheable half of its list
|
|
465
|
+
* metadata: everything except `status` (which depends on `now`). The caller
|
|
466
|
+
* layers status on via {@link statusFromMidTurn}, and can cache this result
|
|
467
|
+
* keyed by (path, mtime, size) so an unchanged transcript is never re-read. */
|
|
468
|
+
function claudeSessionBaseFromFile(
|
|
469
|
+
filePath: string,
|
|
470
|
+
cwd: string,
|
|
471
|
+
sessionId: string,
|
|
472
|
+
mtimeMs: number,
|
|
473
|
+
): { base: Record<string, unknown>; midTurn: boolean } {
|
|
448
474
|
const text = readFileSync(filePath, "utf8");
|
|
449
475
|
const parsed = parseClaudeJsonlSession({
|
|
450
476
|
text,
|
|
451
477
|
cwd,
|
|
452
478
|
sessionId,
|
|
453
|
-
fallbackUpdatedAt:
|
|
479
|
+
fallbackUpdatedAt: mtimeMs,
|
|
454
480
|
});
|
|
455
481
|
const thread = asRecord(parsed.thread) ?? {};
|
|
456
|
-
|
|
482
|
+
const base: Record<string, unknown> = {
|
|
457
483
|
id: sessionId,
|
|
458
484
|
cwd: stringField(thread, ["cwd", "workingDirectory", "workspacePath"]) ?? cwd,
|
|
459
485
|
title: stringField(thread, ["title", "preview"]),
|
|
460
486
|
model: stringField(thread, ["model"]),
|
|
461
487
|
createdAt: parseTimestamp(thread.createdAt),
|
|
462
|
-
lastActivityAt: parseTimestamp(thread.updatedAt) ??
|
|
463
|
-
lastModified:
|
|
488
|
+
lastActivityAt: parseTimestamp(thread.updatedAt) ?? mtimeMs,
|
|
489
|
+
lastModified: mtimeMs,
|
|
464
490
|
usage: asRecord(thread.usage),
|
|
465
|
-
// Live status read straight from the transcript, so a session another
|
|
466
|
-
// `claude` process is actively driving shows as "running" in the list
|
|
467
|
-
// rather than the hardcoded "idle" the workspace would otherwise assign.
|
|
468
|
-
status: deriveTranscriptStatus(text, stat.mtimeMs, Date.now()),
|
|
469
491
|
};
|
|
492
|
+
return { base, midTurn: deriveTranscriptMidTurn(text) };
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
function claudeSessionMetadataFromFile(filePath: string, cwd: string, sessionId: string): Record<string, unknown> {
|
|
496
|
+
const stat = statSync(filePath);
|
|
497
|
+
const { base, midTurn } = claudeSessionBaseFromFile(filePath, cwd, sessionId, stat.mtimeMs);
|
|
498
|
+
// Live status read straight from the transcript, so a session another
|
|
499
|
+
// `claude` process is actively driving shows as "running" in the list
|
|
500
|
+
// rather than the hardcoded "idle" the workspace would otherwise assign.
|
|
501
|
+
return { ...base, status: statusFromMidTurn(midTurn, stat.mtimeMs, Date.now()) };
|
|
470
502
|
}
|
|
471
503
|
|
|
472
504
|
function isInsideCwd(cwd: string, candidate: string): boolean {
|
|
@@ -525,6 +557,13 @@ export class ClaudeSdkClient {
|
|
|
525
557
|
private claudeSessionId: string | undefined;
|
|
526
558
|
private abortController: AbortController | undefined;
|
|
527
559
|
private permissionWaiters = new Map<string, (outcome: "allow" | "deny") => void>();
|
|
560
|
+
// Per-file cache for listSessions: an unchanged transcript (same mtime+size)
|
|
561
|
+
// is never re-read or re-parsed. fs.watch re-syncs fire every ~1.5s while any
|
|
562
|
+
// session is active, and ~/.claude/projects can hold hundreds of old
|
|
563
|
+
// transcripts — without this, each sync would readFileSync + fully parse
|
|
564
|
+
// every one of them (the "scan storm"). Only the file being actively appended
|
|
565
|
+
// to changes, so the steady-state cost drops to stat()+status per file.
|
|
566
|
+
private sessionMetaCache = new Map<string, { mtimeMs: number; size: number; base: Record<string, unknown>; midTurn: boolean }>();
|
|
528
567
|
|
|
529
568
|
constructor(
|
|
530
569
|
private readonly input: {
|
|
@@ -602,6 +641,61 @@ export class ClaudeSdkClient {
|
|
|
602
641
|
.find((candidate) => existsSync(candidate));
|
|
603
642
|
}
|
|
604
643
|
|
|
644
|
+
/** Fork a session: copy the source transcript into a NEW session file,
|
|
645
|
+
* truncated to include everything up to and including the turn `uptoTurnId`
|
|
646
|
+
* (omitted → full clone). Claude has no native fork primitive, so this
|
|
647
|
+
* simulates one by writing a fresh <uuid>.jsonl alongside the source. The
|
|
648
|
+
* source file is NEVER modified. Turn ids match the per-line uuid/id (or the
|
|
649
|
+
* `claude-history-<n>` fallback) that parseClaudeJsonlSession assigns, where
|
|
650
|
+
* <n> counts non-empty lines — replicated here so the cut lands exactly on
|
|
651
|
+
* the turn the client asked for. Returns the new session id, or undefined if
|
|
652
|
+
* the source can't be read or the new file can't be created. */
|
|
653
|
+
forkSession(input: { sourceSessionId: string; uptoTurnId?: string }): { sessionId: string } | undefined {
|
|
654
|
+
const sourceFile = this.resolveSessionFile(input.sourceSessionId);
|
|
655
|
+
if (!sourceFile) return undefined;
|
|
656
|
+
let text: string;
|
|
657
|
+
try {
|
|
658
|
+
text = readFileSync(sourceFile, "utf8");
|
|
659
|
+
} catch {
|
|
660
|
+
return undefined;
|
|
661
|
+
}
|
|
662
|
+
const lines = text.split("\n");
|
|
663
|
+
let cutIndex = lines.length - 1; // default: keep everything (full clone)
|
|
664
|
+
if (input.uptoTurnId) {
|
|
665
|
+
let nonEmpty = 0;
|
|
666
|
+
let found = -1;
|
|
667
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
668
|
+
const line = lines[i]?.trim();
|
|
669
|
+
if (!line) continue;
|
|
670
|
+
nonEmpty += 1;
|
|
671
|
+
let turnId: string;
|
|
672
|
+
try {
|
|
673
|
+
const rec = asRecord(JSON.parse(line));
|
|
674
|
+
turnId = stringField(rec, ["uuid", "id"]) ?? `claude-history-${nonEmpty}`;
|
|
675
|
+
} catch {
|
|
676
|
+
continue; // unparseable line — parser skips it too (index still bumped)
|
|
677
|
+
}
|
|
678
|
+
if (turnId === input.uptoTurnId) {
|
|
679
|
+
found = i;
|
|
680
|
+
break;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
if (found < 0) return undefined; // turn not found — don't silently full-clone
|
|
684
|
+
cutIndex = found;
|
|
685
|
+
}
|
|
686
|
+
const truncated = lines.slice(0, cutIndex + 1).join("\n") + "\n";
|
|
687
|
+
const newId = randomUUID();
|
|
688
|
+
const dir = claudeProjectDir(this.input.cwd);
|
|
689
|
+
const newPath = join(dir, `${newId}.jsonl`);
|
|
690
|
+
try {
|
|
691
|
+
// wx: fail if it somehow already exists — never overwrite.
|
|
692
|
+
writeFileSync(newPath, truncated, { flag: "wx" });
|
|
693
|
+
} catch {
|
|
694
|
+
return undefined;
|
|
695
|
+
}
|
|
696
|
+
return { sessionId: newId };
|
|
697
|
+
}
|
|
698
|
+
|
|
605
699
|
/** Read a session's last-known settings (permission mode, plan mode) straight
|
|
606
700
|
* from its on-disk transcript, so opening a session LinkShell never drove
|
|
607
701
|
* shows the config it actually ran with instead of UI defaults. Claude
|
|
@@ -837,6 +931,8 @@ export class ClaudeSdkClient {
|
|
|
837
931
|
async listSessions(): Promise<unknown> {
|
|
838
932
|
const sessions: Array<Record<string, unknown>> = [];
|
|
839
933
|
const seen = new Set<string>();
|
|
934
|
+
const now = Date.now();
|
|
935
|
+
const liveKeys = new Set<string>();
|
|
840
936
|
for (const projectDir of claudeProjectDirs(this.input.cwd)) {
|
|
841
937
|
try {
|
|
842
938
|
for (const entry of readdirSync(projectDir)) {
|
|
@@ -844,12 +940,36 @@ export class ClaudeSdkClient {
|
|
|
844
940
|
const sessionId = entry.replace(".jsonl", "");
|
|
845
941
|
if (seen.has(sessionId)) continue;
|
|
846
942
|
seen.add(sessionId);
|
|
847
|
-
|
|
943
|
+
const filePath = join(projectDir, entry);
|
|
944
|
+
let stat;
|
|
945
|
+
try {
|
|
946
|
+
stat = statSync(filePath);
|
|
947
|
+
} catch {
|
|
948
|
+
continue; // vanished between readdir and stat
|
|
949
|
+
}
|
|
950
|
+
liveKeys.add(filePath);
|
|
951
|
+
let cached = this.sessionMetaCache.get(filePath);
|
|
952
|
+
if (!cached || cached.mtimeMs !== stat.mtimeMs || cached.size !== stat.size) {
|
|
953
|
+
// Miss or stale: re-read + re-parse this ONE file, refresh the cache.
|
|
954
|
+
const { base, midTurn } = claudeSessionBaseFromFile(filePath, this.input.cwd, sessionId, stat.mtimeMs);
|
|
955
|
+
cached = { mtimeMs: stat.mtimeMs, size: stat.size, base, midTurn };
|
|
956
|
+
this.sessionMetaCache.set(filePath, cached);
|
|
957
|
+
}
|
|
958
|
+
// status is clock-dependent, so recompute it every call (cheap) even
|
|
959
|
+
// on a cache hit — a running session goes idle purely by time passing.
|
|
960
|
+
sessions.push({ ...cached.base, status: statusFromMidTurn(cached.midTurn, stat.mtimeMs, now) });
|
|
848
961
|
}
|
|
849
962
|
} catch {
|
|
850
963
|
// Ignore unreadable Claude project storage.
|
|
851
964
|
}
|
|
852
965
|
}
|
|
966
|
+
// Drop cache entries for transcripts that no longer exist so the map can't
|
|
967
|
+
// grow without bound across a long-lived process.
|
|
968
|
+
if (this.sessionMetaCache.size > liveKeys.size) {
|
|
969
|
+
for (const key of this.sessionMetaCache.keys()) {
|
|
970
|
+
if (!liveKeys.has(key)) this.sessionMetaCache.delete(key);
|
|
971
|
+
}
|
|
972
|
+
}
|
|
853
973
|
return { sessions };
|
|
854
974
|
}
|
|
855
975
|
|
|
@@ -895,6 +1015,16 @@ export class ClaudeSdkClient {
|
|
|
895
1015
|
} catch {
|
|
896
1016
|
// supportedCommands() unavailable or failed — fall back to static defaults.
|
|
897
1017
|
}
|
|
1018
|
+
// Discover MCP server status the same best-effort way. Older SDKs
|
|
1019
|
+
// without mcpServerStatus() just leave mcpServers undefined; live
|
|
1020
|
+
// startupStatus events still populate it. Shape is passed through
|
|
1021
|
+
// verbatim to the workspace parser, which tolerates array/record forms.
|
|
1022
|
+
let mcpServers: unknown;
|
|
1023
|
+
try {
|
|
1024
|
+
mcpServers = await (q as unknown as { mcpServerStatus?: () => Promise<unknown> }).mcpServerStatus?.();
|
|
1025
|
+
} catch {
|
|
1026
|
+
// mcpServerStatus() unavailable or failed — rely on live events.
|
|
1027
|
+
}
|
|
898
1028
|
if (sdkModels.length > 0) {
|
|
899
1029
|
// Filter to admin-configured allowlist if present, then map to our format.
|
|
900
1030
|
const allow = availableModels;
|
|
@@ -905,16 +1035,18 @@ export class ClaudeSdkClient {
|
|
|
905
1035
|
defaultModel,
|
|
906
1036
|
models: filtered.map((m) => ({ id: m.value, label: m.displayName || m.value })),
|
|
907
1037
|
...(commands ? { commands } : {}),
|
|
1038
|
+
...(mcpServers ? { mcpServers } : {}),
|
|
908
1039
|
};
|
|
909
1040
|
}
|
|
910
1041
|
// No models surfaced, but commands may still be present — return them
|
|
911
1042
|
// so the command palette stays in sync even when the model list is empty.
|
|
912
|
-
if (commands) {
|
|
1043
|
+
if (commands || mcpServers) {
|
|
913
1044
|
const fallbackModels = availableModels ?? DEFAULT_FALLBACK_MODELS;
|
|
914
1045
|
return {
|
|
915
1046
|
defaultModel,
|
|
916
1047
|
models: toModelEntries(fallbackModels),
|
|
917
|
-
commands,
|
|
1048
|
+
...(commands ? { commands } : {}),
|
|
1049
|
+
...(mcpServers ? { mcpServers } : {}),
|
|
918
1050
|
};
|
|
919
1051
|
}
|
|
920
1052
|
} catch {
|
|
@@ -124,6 +124,10 @@ export class ClaudeStreamJsonClient {
|
|
|
124
124
|
private child: ChildProcessWithoutNullStreams | undefined;
|
|
125
125
|
private claudeSessionId: string | undefined;
|
|
126
126
|
private pendingCancel = false;
|
|
127
|
+
// Per-file cache for listSessions: skip re-reading/parsing an unchanged
|
|
128
|
+
// transcript (same mtime+size). fs.watch re-syncs fire every ~1.5s, so
|
|
129
|
+
// without this each sync would re-parse every transcript in ~/.claude/projects.
|
|
130
|
+
private sessionMetaCache = new Map<string, { mtimeMs: number; size: number; entry: Record<string, unknown> }>();
|
|
127
131
|
|
|
128
132
|
constructor(
|
|
129
133
|
private readonly input: {
|
|
@@ -537,6 +541,7 @@ export class ClaudeStreamJsonClient {
|
|
|
537
541
|
async listSessions(): Promise<unknown> {
|
|
538
542
|
const sessions: Array<Record<string, unknown>> = [];
|
|
539
543
|
const seen = new Set<string>();
|
|
544
|
+
const liveKeys = new Set<string>();
|
|
540
545
|
for (const projectDir of claudeProjectDirs(this.input.cwd)) {
|
|
541
546
|
try {
|
|
542
547
|
for (const entry of readdirSync(projectDir)) {
|
|
@@ -545,30 +550,48 @@ export class ClaudeStreamJsonClient {
|
|
|
545
550
|
if (seen.has(sessionId)) continue;
|
|
546
551
|
seen.add(sessionId);
|
|
547
552
|
const filePath = join(projectDir, entry);
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
553
|
+
let stat;
|
|
554
|
+
try {
|
|
555
|
+
stat = statSync(filePath);
|
|
556
|
+
} catch {
|
|
557
|
+
continue; // vanished between readdir and stat
|
|
558
|
+
}
|
|
559
|
+
liveKeys.add(filePath);
|
|
560
|
+
let cached = this.sessionMetaCache.get(filePath);
|
|
561
|
+
if (!cached || cached.mtimeMs !== stat.mtimeMs || cached.size !== stat.size) {
|
|
562
|
+
const parsed = parseClaudeJsonlSession({
|
|
563
|
+
text: readFileSync(filePath, "utf8"),
|
|
564
|
+
cwd: this.input.cwd,
|
|
565
|
+
sessionId,
|
|
566
|
+
fallbackUpdatedAt: stat.mtimeMs,
|
|
567
|
+
});
|
|
568
|
+
const thread = parsed.thread && typeof parsed.thread === "object"
|
|
569
|
+
? parsed.thread as Record<string, unknown>
|
|
570
|
+
: {};
|
|
571
|
+
const item: Record<string, unknown> = {
|
|
572
|
+
id: sessionId,
|
|
573
|
+
cwd: stringField(thread, ["cwd", "workingDirectory", "workspacePath"]) ?? this.input.cwd,
|
|
574
|
+
title: stringField(thread, ["title", "preview"]),
|
|
575
|
+
model: stringField(thread, ["model"]),
|
|
576
|
+
createdAt: thread.createdAt,
|
|
577
|
+
lastActivityAt: thread.updatedAt ?? stat.mtimeMs,
|
|
578
|
+
lastModified: stat.mtimeMs,
|
|
579
|
+
};
|
|
580
|
+
cached = { mtimeMs: stat.mtimeMs, size: stat.size, entry: item };
|
|
581
|
+
this.sessionMetaCache.set(filePath, cached);
|
|
582
|
+
}
|
|
583
|
+
sessions.push(cached.entry);
|
|
567
584
|
}
|
|
568
585
|
} catch {
|
|
569
586
|
// directory read failed
|
|
570
587
|
}
|
|
571
588
|
}
|
|
589
|
+
// Prune cache entries for transcripts that no longer exist.
|
|
590
|
+
if (this.sessionMetaCache.size > liveKeys.size) {
|
|
591
|
+
for (const key of this.sessionMetaCache.keys()) {
|
|
592
|
+
if (!liveKeys.has(key)) this.sessionMetaCache.delete(key);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
572
595
|
|
|
573
596
|
return { sessions };
|
|
574
597
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
@import"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap";/**
|
|
2
|
+
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
|
3
|
+
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
|
4
|
+
* https://github.com/chjj/term.js
|
|
5
|
+
* @license MIT
|
|
6
|
+
*
|
|
7
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
* in the Software without restriction, including without limitation the rights
|
|
10
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
* furnished to do so, subject to the following conditions:
|
|
13
|
+
*
|
|
14
|
+
* The above copyright notice and this permission notice shall be included in
|
|
15
|
+
* all copies or substantial portions of the Software.
|
|
16
|
+
*
|
|
17
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
23
|
+
* THE SOFTWARE.
|
|
24
|
+
*
|
|
25
|
+
* Originally forked from (with the author's permission):
|
|
26
|
+
* Fabrice Bellard's javascript vt100 for jslinux:
|
|
27
|
+
* http://bellard.org/jslinux/
|
|
28
|
+
* Copyright (c) 2011 Fabrice Bellard
|
|
29
|
+
* The original design remains. The terminal itself
|
|
30
|
+
* has been extended to include xterm CSI codes, among
|
|
31
|
+
* other features.
|
|
32
|
+
*/.xterm{cursor:text;position:relative;-moz-user-select:none;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm .xterm-scroll-area{visibility:hidden}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::-moz-selection{color:transparent}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{-webkit-user-select:text;-moz-user-select:text;user-select:text;white-space:pre}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{-webkit-text-decoration:double underline;text-decoration:double underline}.xterm-underline-3{-webkit-text-decoration:wavy underline;text-decoration:wavy underline}.xterm-underline-4{-webkit-text-decoration:dotted underline;text-decoration:dotted underline}.xterm-underline-5{-webkit-text-decoration:dashed underline;text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{-webkit-text-decoration:overline double underline;text-decoration:overline double underline}.xterm-overline.xterm-underline-3{-webkit-text-decoration:overline wavy underline;text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{-webkit-text-decoration:overline dotted underline;text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{-webkit-text-decoration:overline dashed underline;text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}*,: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: }/*! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com
|
|
33
|
+
*/*,: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:Inter,system-ui,-apple-system,Segoe UI,sans-serif;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:JetBrains Mono,ui-monospace,SFMono-Regular,Menlo,Consolas,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}:root,[data-theme=dark]{color-scheme:dark;--c-canvas: 11 13 15;--c-surface: 22 24 28;--c-surface-raised: 28 31 36;--c-surface-overlay: 35 38 44;--c-border: 42 46 53;--c-border-strong: 56 62 70;--c-content-primary: 233 235 238;--c-content-secondary: 158 165 173;--c-content-muted: 112 118 126;--c-content-faint: 78 83 90;--c-brand: 59 107 97;--c-brand-light: 78 138 126;--c-brand-dark: 42 79 71;--c-accent: 45 212 191;--c-accent-dim: 31 148 136;--c-diff-add: 31 61 43;--c-diff-add-text: 95 211 138;--c-diff-remove: 61 31 36;--c-diff-remove-text: 240 112 127;--c-success: 16 185 129;--c-warning: 245 158 11;--c-danger: 239 68 68;--glass-bg: 18 20 23;--body-wash-1: rgba(45, 212, 191, .05);--body-wash-2: rgba(59, 107, 97, .04)}[data-theme=light]{color-scheme:light;--c-canvas: 255 255 255;--c-surface: 255 255 255;--c-surface-raised: 248 248 247;--c-surface-overlay: 241 241 239;--c-border: 229 229 226;--c-border-strong: 212 212 208;--c-content-primary: 33 33 33;--c-content-secondary: 90 90 88;--c-content-muted: 130 130 126;--c-content-faint: 168 168 163;--c-brand: 47 92 83;--c-brand-light: 62 120 109;--c-brand-dark: 36 70 63;--c-accent: 17 122 110;--c-accent-dim: 15 105 95;--c-diff-add: 230 246 235;--c-diff-add-text: 30 120 78;--c-diff-remove: 252 230 232;--c-diff-remove-text: 188 50 64;--c-success: 22 128 84;--c-warning: 176 110 20;--c-danger: 196 48 48;--glass-bg: 255 255 255;--body-wash-1: transparent;--body-wash-2: transparent}html,body,#root{height:100%}body{--tw-bg-opacity: 1;background-color:rgb(var(--c-canvas) / var(--tw-bg-opacity, 1));font-family:Inter,system-ui,-apple-system,Segoe UI,sans-serif;--tw-text-opacity: 1;color:rgb(var(--c-content-primary) / var(--tw-text-opacity, 1));-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background-image:radial-gradient(120% 80% at 50% -10%,var(--body-wash-1),transparent 60%),radial-gradient(100% 60% at 100% 100%,var(--body-wash-2),transparent 55%);background-attachment:fixed}::-moz-selection{background:rgb(var(--c-accent) / .25)}::selection{background:rgb(var(--c-accent) / .25)}*{scrollbar-width:thin;scrollbar-color:rgb(var(--c-border-strong)) transparent}*::-webkit-scrollbar{width:8px;height:8px}*::-webkit-scrollbar-thumb{background:rgb(var(--c-border-strong));border-radius:9999px;border:2px solid transparent;background-clip:content-box}*::-webkit-scrollbar-thumb:hover{background:rgb(var(--c-content-faint));background-clip:content-box}*::-webkit-scrollbar-track{background:transparent}.container{width:100%}@media(min-width:640px){.container{max-width:640px}}@media(min-width:768px){.container{max-width:768px}}@media(min-width:1024px){.container{max-width:1024px}}@media(min-width:1280px){.container{max-width:1280px}}@media(min-width:1536px){.container{max-width:1536px}}.codex-card{border-radius:.75rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--c-border) / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(var(--c-surface) / var(--tw-bg-opacity, 1));box-shadow:0 1px rgb(var(--c-content-primary) / .03) inset,0 1px 2px #0000002e}.codex-card-raised{border-radius:.75rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--c-border) / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(var(--c-surface-raised) / var(--tw-bg-opacity, 1));box-shadow:0 1px rgb(var(--c-content-primary) / .04) inset,0 8px 28px -8px #00000047}.glass-bar{background:rgb(var(--glass-bg) / .6);backdrop-filter:saturate(140%) blur(12px);-webkit-backdrop-filter:saturate(140%) blur(12px)}.codex-input{width:100%;border-radius:.75rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--c-border) / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(var(--c-surface-raised) / var(--tw-bg-opacity, 1));padding:.625rem .875rem;font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(var(--c-content-primary) / var(--tw-text-opacity, 1))}.codex-input::-moz-placeholder{--tw-placeholder-opacity: 1;color:rgb(var(--c-content-muted) / var(--tw-placeholder-opacity, 1))}.codex-input::placeholder{--tw-placeholder-opacity: 1;color:rgb(var(--c-content-muted) / var(--tw-placeholder-opacity, 1))}.codex-input{outline:2px solid transparent;outline-offset:2px;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.codex-input:focus{--tw-border-opacity: 1;border-color:rgb(var(--c-accent-dim) / var(--tw-border-opacity, 1));--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(2px + 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);--tw-ring-color: rgb(var(--c-accent) / .2)}.codex-btn-primary{display:inline-flex;height:2.25rem;cursor:pointer;align-items:center;justify-content:center;gap:.375rem;border-radius:.5rem;padding-left:.875rem;padding-right:.875rem;font-size:.875rem;line-height:1.25rem;font-weight:500;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.codex-btn-primary:focus-visible{outline:2px solid transparent;outline-offset:2px;--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(2px + 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);--tw-ring-color: rgb(var(--c-accent) / .4)}.codex-btn-primary:disabled{pointer-events:none;opacity:.4}.codex-btn-primary{--tw-bg-opacity: 1;background-color:rgb(var(--c-accent-dim) / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.codex-btn-primary:hover{--tw-bg-opacity: 1;background-color:rgb(var(--c-accent) / var(--tw-bg-opacity, 1))}.codex-btn-primary{box-shadow:0 1px 2px #0000001f}.codex-btn-ghost{display:inline-flex;height:2.25rem;cursor:pointer;align-items:center;justify-content:center;gap:.375rem;border-radius:.5rem;padding-left:.875rem;padding-right:.875rem;font-size:.875rem;line-height:1.25rem;font-weight:500;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.codex-btn-ghost:focus-visible{outline:2px solid transparent;outline-offset:2px;--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(2px + 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);--tw-ring-color: rgb(var(--c-accent) / .4)}.codex-btn-ghost:disabled{pointer-events:none;opacity:.4}.codex-btn-ghost{--tw-text-opacity: 1;color:rgb(var(--c-content-secondary) / var(--tw-text-opacity, 1))}.codex-btn-ghost:hover{--tw-bg-opacity: 1;background-color:rgb(var(--c-surface-overlay) / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(var(--c-content-primary) / var(--tw-text-opacity, 1))}.codex-btn-outline{display:inline-flex;height:2.25rem;cursor:pointer;align-items:center;justify-content:center;gap:.375rem;border-radius:.5rem;padding-left:.875rem;padding-right:.875rem;font-size:.875rem;line-height:1.25rem;font-weight:500;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.codex-btn-outline:focus-visible{outline:2px solid transparent;outline-offset:2px;--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(2px + 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);--tw-ring-color: rgb(var(--c-accent) / .4)}.codex-btn-outline:disabled{pointer-events:none;opacity:.4}.codex-btn-outline{border-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--c-border) / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(var(--c-surface) / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(var(--c-content-secondary) / var(--tw-text-opacity, 1))}.codex-btn-outline:hover{--tw-border-opacity: 1;border-color:rgb(var(--c-border-strong) / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(var(--c-surface-overlay) / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(var(--c-content-primary) / var(--tw-text-opacity, 1))}.tree-row{display:flex;width:100%;cursor:pointer;align-items:center;gap:.625rem;border-radius:.5rem;padding:.5rem .75rem;text-align:left;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.tree-row:hover{--tw-bg-opacity: 1;background-color:rgb(var(--c-surface-overlay) / var(--tw-bg-opacity, 1))}.tree-row-active{--tw-bg-opacity: 1;background-color:rgb(var(--c-surface-overlay) / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(var(--c-content-primary) / var(--tw-text-opacity, 1))}.codex-chip{display:inline-flex;align-items:center;gap:.25rem;border-radius:9999px;border-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--c-border) / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(var(--c-surface-raised) / var(--tw-bg-opacity, 1));padding:.125rem .5rem;font-family:JetBrains Mono,ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.6875rem;line-height:1rem;--tw-text-opacity: 1;color:rgb(var(--c-content-secondary) / var(--tw-text-opacity, 1))}.xterm-host,.xterm-host .xterm,.xterm-host .xterm-viewport{height:100%;width:100%}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.visible{visibility:visible}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.inset-y-0{top:0;bottom:0}.-right-1\.5{right:-.375rem}.-top-1\.5{top:-.375rem}.bottom-4{bottom:1rem}.bottom-full{bottom:100%}.left-0{left:0}.right-0{right:0}.right-1\.5{right:.375rem}.right-2{right:.5rem}.right-4{right:1rem}.top-0{top:0}.top-1\.5{top:.375rem}.top-2{top:.5rem}.top-9{top:2.25rem}.top-full{top:100%}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.z-\[60\]{z-index:60}.mx-1{margin-left:.25rem;margin-right:.25rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.-mt-1{margin-top:-.25rem}.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-2{margin-right:.5rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-2{margin-top:.5rem}.mt-2\.5{margin-top:.625rem}.mt-3{margin-top:.75rem}.line-clamp-1{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.h-1{height:.25rem}.h-1\.5{height:.375rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-3{height:.75rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-\[100dvh\]{height:100dvh}.h-full{height:100%}.h-px{height:1px}.max-h-32{max-height:8rem}.max-h-40{max-height:10rem}.max-h-48{max-height:12rem}.max-h-60{max-height:15rem}.max-h-72{max-height:18rem}.max-h-\[50vh\]{max-height:50vh}.max-h-\[80vh\]{max-height:80vh}.min-h-0{min-height:0px}.min-h-screen{min-height:100vh}.w-1{width:.25rem}.w-1\.5{width:.375rem}.w-12{width:3rem}.w-14{width:3.5rem}.w-2\.5{width:.625rem}.w-28{width:7rem}.w-3{width:.75rem}.w-36{width:9rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-7{width:1.75rem}.w-8{width:2rem}.w-80{width:20rem}.w-9{width:2.25rem}.w-\[390px\]{width:390px}.w-\[82\%\]{width:82%}.w-full{width:100%}.min-w-0{min-width:0px}.min-w-\[13rem\]{min-width:13rem}.min-w-\[8rem\]{min-width:8rem}.max-w-3xl{max-width:48rem}.max-w-5xl{max-width:64rem}.max-w-\[200px\]{max-width:200px}.max-w-\[46rem\]{max-width:46rem}.max-w-\[7rem\]{max-width:7rem}.max-w-\[85\%\]{max-width:85%}.max-w-full{max-width:100%}.max-w-lg{max-width:32rem}.max-w-sm{max-width:24rem}.max-w-xl{max-width:36rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.basis-full{flex-basis:100%}.rotate-180{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes drawer-in{0%{transform:translate(-100%)}to{transform:translate(0)}}.animate-drawer-in{animation:drawer-in .24s cubic-bezier(.16,1,.3,1)}@keyframes fade-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.animate-fade-in{animation:fade-in .2s ease-out}@keyframes panel-in-right{0%{opacity:0;transform:translate(30px)}to{opacity:1;transform:translate(0)}}.animate-panel-in-right{animation:panel-in-right .22s cubic-bezier(.16,1,.3,1) both}@keyframes panel-in-up{0%{opacity:0;transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}.animate-panel-in-up{animation:panel-in-up .24s cubic-bezier(.16,1,.3,1) both}@keyframes panel-out-down{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(100%)}}.animate-panel-out-down{animation:panel-out-down .24s cubic-bezier(.16,1,.3,1) both}@keyframes panel-out-right{0%{opacity:1;transform:translate(0)}to{opacity:0;transform:translate(30px)}}.animate-panel-out-right{animation:panel-out-right .22s cubic-bezier(.16,1,.3,1) both}@keyframes pulse-dot{0%,to{opacity:.4}50%{opacity:1}}.animate-pulse-dot{animation:pulse-dot 1.2s ease-in-out infinite}@keyframes slide-in{0%{opacity:0;transform:translate(8px)}to{opacity:1;transform:translate(0)}}.animate-slide-in{animation:slide-in .22s cubic-bezier(.16,1,.3,1)}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-col-resize{cursor:col-resize}.cursor-crosshair{cursor:crosshair}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.cursor-row-resize{cursor:row-resize}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize-none{resize:none}.resize{resize:both}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.gap-y-1\.5{row-gap:.375rem}.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-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * 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))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.divide-x>:not([hidden])~:not([hidden]){--tw-divide-x-reverse: 0;border-right-width:calc(1px * var(--tw-divide-x-reverse));border-left-width:calc(1px * calc(1 - var(--tw-divide-x-reverse)))}.divide-border>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:rgb(var(--c-border) / var(--tw-divide-opacity, 1))}.self-start{align-self:flex-start}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-x-hidden{overflow-x:hidden}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre{white-space:pre}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-\[3px\]{border-radius:3px}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-sm{border-radius:.125rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-2{border-width:2px}.border-x{border-left-width:1px;border-right-width:1px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-accent{--tw-border-opacity: 1;border-color:rgb(var(--c-accent) / var(--tw-border-opacity, 1))}.border-accent-dim\/40{border-color:rgb(var(--c-accent-dim) / .4)}.border-accent\/30{border-color:rgb(var(--c-accent) / .3)}.border-border{--tw-border-opacity: 1;border-color:rgb(var(--c-border) / var(--tw-border-opacity, 1))}.border-border-strong{--tw-border-opacity: 1;border-color:rgb(var(--c-border-strong) / var(--tw-border-opacity, 1))}.border-content-faint{--tw-border-opacity: 1;border-color:rgb(var(--c-content-faint) / var(--tw-border-opacity, 1))}.border-danger\/30{border-color:rgb(var(--c-danger) / .3)}.border-danger\/40{border-color:rgb(var(--c-danger) / .4)}.border-success\/30{border-color:rgb(var(--c-success) / .3)}.border-warning\/40{border-color:rgb(var(--c-warning) / .4)}.border-t-accent{--tw-border-opacity: 1;border-top-color:rgb(var(--c-accent) / var(--tw-border-opacity, 1))}.bg-accent{--tw-bg-opacity: 1;background-color:rgb(var(--c-accent) / var(--tw-bg-opacity, 1))}.bg-accent-dim{--tw-bg-opacity: 1;background-color:rgb(var(--c-accent-dim) / var(--tw-bg-opacity, 1))}.bg-accent\/10{background-color:rgb(var(--c-accent) / .1)}.bg-black\/60{background-color:#0009}.bg-border{--tw-bg-opacity: 1;background-color:rgb(var(--c-border) / var(--tw-bg-opacity, 1))}.bg-canvas{--tw-bg-opacity: 1;background-color:rgb(var(--c-canvas) / var(--tw-bg-opacity, 1))}.bg-canvas\/60{background-color:rgb(var(--c-canvas) / .6)}.bg-canvas\/80{background-color:rgb(var(--c-canvas) / .8)}.bg-canvas\/95{background-color:rgb(var(--c-canvas) / .95)}.bg-content-faint{--tw-bg-opacity: 1;background-color:rgb(var(--c-content-faint) / var(--tw-bg-opacity, 1))}.bg-current{background-color:currentColor}.bg-danger{--tw-bg-opacity: 1;background-color:rgb(var(--c-danger) / var(--tw-bg-opacity, 1))}.bg-danger\/10{background-color:rgb(var(--c-danger) / .1)}.bg-diff-add{--tw-bg-opacity: 1;background-color:rgb(var(--c-diff-add) / var(--tw-bg-opacity, 1))}.bg-diff-remove{--tw-bg-opacity: 1;background-color:rgb(var(--c-diff-remove) / var(--tw-bg-opacity, 1))}.bg-success{--tw-bg-opacity: 1;background-color:rgb(var(--c-success) / var(--tw-bg-opacity, 1))}.bg-success\/10{background-color:rgb(var(--c-success) / .1)}.bg-surface{--tw-bg-opacity: 1;background-color:rgb(var(--c-surface) / var(--tw-bg-opacity, 1))}.bg-surface-overlay{--tw-bg-opacity: 1;background-color:rgb(var(--c-surface-overlay) / var(--tw-bg-opacity, 1))}.bg-surface-raised{--tw-bg-opacity: 1;background-color:rgb(var(--c-surface-raised) / var(--tw-bg-opacity, 1))}.bg-surface-raised\/60{background-color:rgb(var(--c-surface-raised) / .6)}.bg-transparent{background-color:transparent}.bg-warning{--tw-bg-opacity: 1;background-color:rgb(var(--c-warning) / var(--tw-bg-opacity, 1))}.bg-warning\/10{background-color:rgb(var(--c-warning) / .1)}.bg-warning\/15{background-color:rgb(var(--c-warning) / .15)}.bg-warning\/30{background-color:rgb(var(--c-warning) / .3)}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.object-contain{-o-object-fit:contain;object-fit:contain}.object-cover{-o-object-fit:cover;object-fit:cover}.p-0\.5{padding:.125rem}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-3\.5{padding:.875rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.px-0{padding-left:0;padding-right:0}.px-0\.5{padding-left:.125rem;padding-right:.125rem}.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-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-3\.5{padding-left:.875rem;padding-right:.875rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.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-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-20{padding-top:5rem;padding-bottom:5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-1{padding-bottom:.25rem}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pb-4{padding-bottom:1rem}.pl-1{padding-left:.25rem}.pl-2{padding-left:.5rem}.pl-3{padding-left:.75rem}.pl-4{padding-left:1rem}.pl-5{padding-left:1.25rem}.pl-7{padding-left:1.75rem}.pr-1{padding-right:.25rem}.pr-3{padding-right:.75rem}.pr-9{padding-right:2.25rem}.pt-1\.5{padding-top:.375rem}.pt-2{padding-top:.5rem}.pt-2\.5{padding-top:.625rem}.pt-\[12vh\]{padding-top:12vh}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:JetBrains Mono,ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}.text-2xs{font-size:.6875rem;line-height:1rem}.text-\[10px\]{font-size:10px}.text-\[13px\]{font-size:13px}.text-\[15px\]{font-size:15px}.text-base{font-size:1rem;line-height:1.5rem}.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-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing: tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-6{line-height:1.5rem}.leading-7{line-height:1.75rem}.leading-\[1\.6\]{line-height:1.6}.leading-relaxed{line-height:1.625}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.tracking-widest{letter-spacing:.1em}.text-accent{--tw-text-opacity: 1;color:rgb(var(--c-accent) / var(--tw-text-opacity, 1))}.text-accent-dim{--tw-text-opacity: 1;color:rgb(var(--c-accent-dim) / var(--tw-text-opacity, 1))}.text-content-faint{--tw-text-opacity: 1;color:rgb(var(--c-content-faint) / var(--tw-text-opacity, 1))}.text-content-muted{--tw-text-opacity: 1;color:rgb(var(--c-content-muted) / var(--tw-text-opacity, 1))}.text-content-primary{--tw-text-opacity: 1;color:rgb(var(--c-content-primary) / var(--tw-text-opacity, 1))}.text-content-secondary{--tw-text-opacity: 1;color:rgb(var(--c-content-secondary) / var(--tw-text-opacity, 1))}.text-danger{--tw-text-opacity: 1;color:rgb(var(--c-danger) / var(--tw-text-opacity, 1))}.text-diff-addText{--tw-text-opacity: 1;color:rgb(var(--c-diff-add-text) / var(--tw-text-opacity, 1))}.text-diff-removeText{--tw-text-opacity: 1;color:rgb(var(--c-diff-remove-text) / var(--tw-text-opacity, 1))}.text-success{--tw-text-opacity: 1;color:rgb(var(--c-success) / var(--tw-text-opacity, 1))}.text-warning{--tw-text-opacity: 1;color:rgb(var(--c-warning) / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.underline{text-decoration-line:underline}.line-through{text-decoration-line:line-through}.underline-offset-2{text-underline-offset:2px}.placeholder-content-muted::-moz-placeholder{--tw-placeholder-opacity: 1;color:rgb(var(--c-content-muted) / var(--tw-placeholder-opacity, 1))}.placeholder-content-muted::placeholder{--tw-placeholder-opacity: 1;color:rgb(var(--c-content-muted) / var(--tw-placeholder-opacity, 1))}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-40{opacity:.4}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.shadow-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.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)}.outline-none{outline:2px solid transparent;outline-offset:2px}.blur{--tw-blur: blur(8px);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)}.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)}.backdrop-blur-sm{--tw-backdrop-blur: blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;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}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-150{transition-duration:.15s}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}@media(hover:none)and (pointer:coarse){[class*="group-hover:opacity-100"]{opacity:1!important}}.focus-within\:border-border-strong:focus-within{--tw-border-opacity: 1;border-color:rgb(var(--c-border-strong) / var(--tw-border-opacity, 1))}.hover\:border-border-strong:hover{--tw-border-opacity: 1;border-color:rgb(var(--c-border-strong) / var(--tw-border-opacity, 1))}.hover\:border-danger:hover{--tw-border-opacity: 1;border-color:rgb(var(--c-danger) / var(--tw-border-opacity, 1))}.hover\:bg-accent:hover{--tw-bg-opacity: 1;background-color:rgb(var(--c-accent) / var(--tw-bg-opacity, 1))}.hover\:bg-accent-dim\/50:hover{background-color:rgb(var(--c-accent-dim) / .5)}.hover\:bg-danger\/10:hover{background-color:rgb(var(--c-danger) / .1)}.hover\:bg-surface-overlay:hover{--tw-bg-opacity: 1;background-color:rgb(var(--c-surface-overlay) / var(--tw-bg-opacity, 1))}.hover\:bg-surface-overlay\/60:hover{background-color:rgb(var(--c-surface-overlay) / .6)}.hover\:bg-surface-raised:hover{--tw-bg-opacity: 1;background-color:rgb(var(--c-surface-raised) / var(--tw-bg-opacity, 1))}.hover\:text-accent:hover{--tw-text-opacity: 1;color:rgb(var(--c-accent) / var(--tw-text-opacity, 1))}.hover\:text-content-primary:hover{--tw-text-opacity: 1;color:rgb(var(--c-content-primary) / var(--tw-text-opacity, 1))}.hover\:text-content-secondary:hover{--tw-text-opacity: 1;color:rgb(var(--c-content-secondary) / var(--tw-text-opacity, 1))}.hover\:text-danger:hover{--tw-text-opacity: 1;color:rgb(var(--c-danger) / var(--tw-text-opacity, 1))}.focus\:border-accent-dim:focus{--tw-border-opacity: 1;border-color:rgb(var(--c-accent-dim) / var(--tw-border-opacity, 1))}.disabled\:cursor-default:disabled{cursor:default}.disabled\:bg-surface-overlay:disabled{--tw-bg-opacity: 1;background-color:rgb(var(--c-surface-overlay) / var(--tw-bg-opacity, 1))}.disabled\:text-content-faint:disabled{--tw-text-opacity: 1;color:rgb(var(--c-content-faint) / var(--tw-text-opacity, 1))}.disabled\:opacity-40:disabled{opacity:.4}.group\/code:hover .group-hover\/code\:opacity-100,.group\/out:hover .group-hover\/out\:opacity-100,.group:hover .group-hover\:opacity-100{opacity:1}@media(min-width:640px){.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.sm\:gap-3{gap:.75rem}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}}@media(min-width:768px){.md\:text-\[15px\]{font-size:15px}}
|