authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-02-11 15:53:31-08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-02-11 15:53:31-08:00
log16b81f72689f4347753762112f76ccd5828fe2fa
tree92c5841054415f1d8a25830cab2d3ac21e30ff80
parent169d06f05b543433278a123b3512fddad05f9f2a
parent94420192359d68c03241f03f47cf8d670abafa15
signature Signed by PGP key B5690EEEBB952194

Merge pull request #3 from pingdotgg/juliusmarminge/git-integration


54 files changed, 2192 insertions(+), 525 deletions(-)

.plans/branch-environment-picker-in-chatview-input.md created+74
......@@ -0,0 +1,74 @@
1# Branch/Environment Picker in ChatView Input
2
3## Summary
4
5Add a secondary toolbar below the ChatView input area (similar to Codex UI) that lets users select the target branch and environment mode (Local vs New worktree) before sending their first message.
6
7## UX
8
9- A toolbar appears **below** the input form (always visible when it's a git repo)
10- Two controls:
11 1. **Environment mode** (left side): toggles between "Local" and "New worktree" — **locked after first message** (no longer clickable, just shows current mode as label)
12 2. **Branch picker** (right side): dropdown showing local branches — **always changeable**, even after messages are sent
13- If not a git repo, the toolbar is hidden entirely (thread uses project cwd as-is)
14
15## Changes
16
17### 0. Install `@tanstack/react-query` in `apps/renderer`
18
19Add dependency + wrap app in `QueryClientProvider`.
20
21### 1. `apps/renderer/src/store.ts` — MODIFY
22
23Add a new action to the reducer:
24
25```ts
26| { type: "SET_THREAD_BRANCH"; threadId: string; branch: string | null; worktreePath: string | null }
27```
28
29Reducer case updates `branch` and `worktreePath` on the thread.
30
31### 2. `apps/renderer/src/components/ChatView.tsx` — MODIFY
32
33**Fetch branches** via `useQuery`:
34
35```ts
36const branchQuery = useQuery({
37 queryKey: ["git-branches", activeProject?.cwd],
38 queryFn: () => api.git.listBranches({ cwd: activeProject!.cwd }),
39 enabled: !!activeProject,
40});
41```
42
43**Local state:**
44
45- `envMode: "local" | "worktree"` — environment mode (local component state)
46
47**UI:** Below the `<form>`, render a toolbar bar (hidden if `!branchQuery.data?.isRepo`):
48
49- Left side: env mode button ("Local" / "New worktree") — disabled after first message (locked in)
50- Right side: branch dropdown from `branchQuery.data.branches`
51- Both styled like existing model picker (small text, chevron, dropdown menus)
52
53**Behavior:**
54
55- Branch picker is always active — changing branch dispatches `SET_THREAD_BRANCH` immediately
56- Env mode is only clickable when `activeThread.messages.length === 0`. After first message, it becomes a static label showing the locked-in mode
57- On first send (`onSend`): if `envMode === "worktree"` and a branch is selected, call `api.git.createWorktree` before starting the session, then dispatch `SET_THREAD_BRANCH` with the worktreePath
58- `ensureSession` already uses `activeThread.worktreePath ?? activeProject.cwd`
59
60### Files to modify
61
621. `apps/renderer/package.json` — add `@tanstack/react-query`
632. `apps/renderer/src/main.tsx` (or App entry) — wrap in `QueryClientProvider`
643. `apps/renderer/src/store.ts` — add `SET_THREAD_BRANCH` action
654. `apps/renderer/src/components/ChatView.tsx` — branch/env picker UI with `useQuery`
66
67## Verification
68
691. `turbo build` — compiles
702. Create a new thread → branch bar appears below input with "Local" + current branch
713. Change branch in dropdown → branch updates on thread
724. Toggle "New worktree" → send message → worktree created, session uses worktree cwd
735. After first message: env mode label locks to "Worktree" (not clickable), branch picker still works
746. Non-git project → no branch bar shown
.plans/git-flows-integration-tests.md created+99
......@@ -0,0 +1,99 @@
1# Git Flows Integration Tests
2
3## Overview
4
5Real integration tests that run actual git commands against temporary repos. No mocking.
6
7## Step 1: Extract git functions into `apps/desktop/src/git.ts`
8
9The git functions (`listGitBranches`, `createGitWorktree`, `removeGitWorktree`, `createGitBranch`, `checkoutGitBranch`, `initGitRepo`) and their helper `runTerminalCommand` are currently private in `main.ts`. Extract them into a new `apps/desktop/src/git.ts` module with named exports.
10
11`main.ts` will import and re-use them — no behavior change, just moving code.
12
13**Files modified:**
14
15- `apps/desktop/src/git.ts` — new file with all git functions exported
16- `apps/desktop/src/main.ts` — import from `./git` instead of defining inline
17
18## Step 2: Create `apps/desktop/src/git.test.ts`
19
20Integration tests using real temp git repos. Each test group creates a fresh temp directory with `git init`, makes commits, creates branches as needed, and cleans up after.
21
22### Setup/teardown pattern
23
24```ts
25import { mkdtemp, rm, writeFile } from "node:fs/promises";
26import { tmpdir } from "node:os";
27import path from "node:path";
28import { afterEach, beforeEach, describe, expect, it } from "vitest";
29import {
30 listGitBranches,
31 createGitBranch,
32 checkoutGitBranch,
33 createGitWorktree,
34 removeGitWorktree,
35 initGitRepo,
36} from "./git";
37
38// Helper: run a raw git command in a dir (for test setup, not under test)
39// Helper: create an initial commit (git needs at least one commit for branches)
40```
41
42### Test groups
43
44**1. initGitRepo**
45
46- Creates a valid git repo in a temp dir
47- listGitBranches reports `isRepo: true` after init
48
49**2. listGitBranches**
50
51- Returns `isRepo: false` for non-git directory
52- Returns the current branch with `current: true`
53- Sorts current branch first
54- Lists multiple branches after creating them
55- `isDefault` is false when no remote (no origin/HEAD)
56
57**3. checkoutGitBranch**
58
59- Checks out an existing branch (current flag moves)
60- Throws when branch doesn't exist
61- Throws when checkout would overwrite uncommitted changes (dirty working tree)
62
63**4. createGitBranch**
64
65- Creates a new branch (appears in listGitBranches)
66- Throws when branch already exists
67
68**5. createGitWorktree + removeGitWorktree**
69
70- Creates a worktree directory at the expected path
71- Worktree has the correct branch checked out
72- Throws when branch is already checked out in another worktree
73- removeGitWorktree cleans up the worktree
74
75**6. Full flow: local branch checkout**
76
77- init → commit → create branch → checkout → verify current
78
79**7. Full flow: worktree creation from selected branch**
80
81- init → commit → create branch → create worktree → verify worktree dir exists and has correct branch
82
83**8. Full flow: thread switching simulation**
84
85- init → commit → create branch-a, branch-b → checkout a → checkout b → checkout a → verify current matches
86
87**9. Full flow: checkout conflict**
88
89- init → commit → create branch → modify file (unstaged) → checkout other branch → expect error
90
91## Verification
92
93```bash
94# Run the git integration tests
95cd apps/desktop && bun run test
96
97# Or just the git test file
98npx vitest run apps/desktop/src/git.test.ts
99```
.plans/git-flows-test-plan.md created+103
......@@ -0,0 +1,103 @@
1# Git Flows Test Plan
2
3## Overview
4
5Add tests for git branch/worktree flows. Two files:
6
71. **Extend** `apps/renderer/src/store.test.ts` — reducer tests for `SET_THREAD_BRANCH`
82. **Create** `apps/renderer/src/git-flows.test.ts` — flow logic tests
9
10All tests are pure Vitest unit tests (no React rendering). They test the reducer directly and simulate handler logic via sequential reducer dispatches + mocked API calls.
11
12## File 1: `apps/renderer/src/store.test.ts` (extend)
13
14Add `describe("SET_THREAD_BRANCH reducer")` with 6 tests:
15
16- Sets branch + worktreePath atomically
17- Clears both to null
18- Updates branch while preserving worktreePath
19- Does not affect other threads (multi-thread state)
20- No-op for nonexistent thread id
21- Does not mutate messages, error, or session fields
22
23Uses existing `makeThread`, `makeState` factories.
24
25## File 2: `apps/renderer/src/git-flows.test.ts` (new)
26
27### Factories
28
29- `makeThread()`, `makeState()`, `makeSession()` — same pattern as store.test.ts
30- `makeBranch()` — creates `GitBranch` objects
31- `makeMessage()` — creates `ChatMessage` objects
32- `makeGitApi()` — returns `{ checkout, createWorktree, createBranch, listBranches }` with `vi.fn()` mocks
33
34### Test groups (~30 tests total)
35
36**1. Local branch checkout flow** (2 tests)
37
38- Successful checkout → SET_THREAD_BRANCH updates branch
39- Checkout failure → SET_ERROR, branch unchanged
40
41**2. Thread branch conflict on send** (3 tests)
42
43- Two threads maintain independent branch state after SET_ACTIVE_THREAD
44- Branch state preserved through multiple thread switches + updates
45- Checkout failure on thread switch sets error only on target thread
46
47**3. Worktree creation on send** (5 tests)
48
49- First message in worktree mode → createWorktree → SET_THREAD_BRANCH with worktreePath
50- No worktree when messages already exist
51- No worktree in local envMode
52- No worktree when worktreePath already set
53- createWorktree failure → SET_ERROR, send aborted, no messages pushed
54
55**4. Env mode locking** (4 tests)
56
57- envLocked=false when no messages
58- envLocked=true with messages
59- Transitions false→true after PUSH_USER_MESSAGE
60- Remains true after SET_ERROR and UPDATE_SESSION
61
62**5. Auto-fill current branch** (3 tests)
63
64- Dispatches SET_THREAD_BRANCH when thread has no branch and current branch exists
65- Does not overwrite existing branch
66- No-op when no branch is marked current
67
68**6. Default branch detection** (2 tests)
69
70- isDefault flag on branch objects
71- current and isDefault can be on different branches
72
73**7. Branch creation + checkout** (3 tests)
74
75- Successful create + checkout updates branch
76- createBranch failure → error, branch unchanged
77- checkout failure after successful create → error, branch unchanged
78
79**8. Session CWD resolution** (3 tests)
80
81- Uses worktreePath when available
82- cwdOverride takes precedence over worktreePath
83- Falls back to project cwd when no worktree
84
85**9. Error handling patterns** (4 tests)
86
87- SET_ERROR sets error on correct thread
88- SET_ERROR with null clears error
89- Error on one thread doesn't affect others
90- Error cleared before successful branch operations
91
92## Verification
93
94```bash
95# Run all renderer tests
96cd apps/renderer && bun run test
97
98# Run just the new test file
99npx vitest run apps/renderer/src/git-flows.test.ts
100
101# Run just the store tests
102npx vitest run apps/renderer/src/store.test.ts
103```
.plans/git-integration-branch-picker-worktrees.md created+115
......@@ -0,0 +1,115 @@
1# Git Integration: Branch Picker + Worktrees
2
3## Summary
4
5Add git integration to let users start new threads from a specific branch, optionally creating a git worktree for isolated agent work.
6
7## UX Flow
8
9- **Left click** "+ New thread" → immediately creates a thread (current behavior, unchanged)
10- **Right click** "+ New thread" → opens a context menu with git options:
11 - List of local branches → clicking one creates a thread on that branch (uses project cwd)
12 - Each branch has a "worktree" sub-option → creates a worktree, then creates thread with worktree as cwd
13- When thread has a worktree, the agent session uses the worktree path as its cwd
14- If git fails (not a repo), context menu shows "Not a git repository" disabled item
15
16## Changes
17
18### 1. `packages/contracts/src/git.ts` — CREATE
19
20New Zod schemas and types:
21
22- `gitListBranchesInputSchema` — `{ cwd: string }`
23- `gitCreateWorktreeInputSchema` — `{ cwd: string, branch: string, path?: string }`
24- `gitRemoveWorktreeInputSchema` — `{ cwd: string, path: string }`
25- `gitBranchSchema` — `{ name: string, current: boolean }`
26- Result types for each
27
28### 2. `packages/contracts/src/ipc.ts` — MODIFY
29
30- Add 3 IPC channels: `git:list-branches`, `git:create-worktree`, `git:remove-worktree`
31- Add `git` namespace to `NativeApi` with `listBranches`, `createWorktree`, `removeWorktree`
32
33### 3. `packages/contracts/src/index.ts` — MODIFY
34
35- Add `export * from "./git"`
36
37### 4. `apps/desktop/src/main.ts` — MODIFY
38
39Add 3 IPC handlers + helper functions:
40
41- `listGitBranches()` — runs `git branch --no-color`, parses output into `{ name, current }[]`
42- `createGitWorktree()` — runs `git worktree add <path> <branch>`, defaults path to `../{repo}-worktrees/{branch}`
43- `removeGitWorktree()` — runs `git worktree remove <path>`
44
45Reuses existing `runTerminalCommand()`.
46
47### 5. `apps/desktop/src/preload.ts` — MODIFY
48
49Add `git` namespace with 3 `ipcRenderer.invoke` calls.
50
51### 6. `apps/renderer/src/types.ts` — MODIFY
52
53Add to `Thread`:
54
55```
56branch: string | null
57worktreePath: string | null
58```
59
60### 7. `apps/renderer/src/persistenceSchema.ts` — MODIFY
61
62- Add optional `branch`/`worktreePath` to persisted thread schema (`.nullable().optional()` for backwards compat)
63- Add V3 schema, update union
64- Update `hydrateThread` to default new fields to `null`
65- Update `toPersistedState` to serialize new fields
66
67### 8. `apps/renderer/src/store.ts` — MODIFY
68
69- Update persisted state key to v3, keep v2 as legacy fallback
70
71### 9. `apps/renderer/src/components/Sidebar.tsx` — MODIFY (main UI work)
72
73- Keep existing left-click `handleNewThread` unchanged (immediate thread creation)
74- Add `onContextMenu` handler to "+ New thread" buttons (both global and per-project)
75- On right-click: fetch branches via `api.git.listBranches`, show a custom context menu
76- Context menu items: branch names, each with a nested option to create with worktree
77- Clicking a branch → creates thread with `branch` set, title = branch name
78- Clicking "with worktree" → calls `api.git.createWorktree` first, then creates thread with `worktreePath`
79- Show branch badge on thread list items
80- If not a git repo, show "Not a git repository" as disabled menu item
81
82Context menu component: a positioned `<div>` with `position: fixed` anchored to the click position, dismissed on click-outside or Escape. Follows the existing dropdown pattern from ChatView's model picker.
83
84### 10. `apps/renderer/src/components/ChatView.tsx` — MODIFY
85
86- Line 157: use `activeThread.worktreePath ?? activeProject.cwd` as session cwd
87- Show branch/worktree badge in header bar
88
89## Implementation Order
90
911. `packages/contracts/src/git.ts` (new schemas)
922. `packages/contracts/src/ipc.ts` + `index.ts` (wire up channels)
933. `apps/desktop/src/main.ts` (git command handlers)
944. `apps/desktop/src/preload.ts` (bridge methods)
955. `apps/renderer/src/types.ts` (Thread type update)
966. `apps/renderer/src/persistenceSchema.ts` + `store.ts` (persistence migration)
977. `apps/renderer/src/components/Sidebar.tsx` (branch picker UI)
988. `apps/renderer/src/components/ChatView.tsx` (worktree cwd + badge)
99
100## Edge Cases
101
102- **Not a git repo**: `git branch` fails → context menu shows "Not a git repository" disabled item
103- **Branch has slashes**: `feature/foo` → worktree dir becomes `feature-foo`
104- **Worktree exists**: git error surfaces to user via inline error message in context menu
105- **No persistence breakage**: `.nullable().optional()` fields parse fine with old data
106
107## Verification
108
1091. `turbo build` — confirm contracts/desktop/renderer all compile
1102. Launch app, add a project pointing to a git repo
1113. Click "+ New thread" → verify branch list loads
1124. Select a branch, click Start → thread created with branch in title
1135. Enable worktree checkbox, pick branch, Start → verify worktree directory created on disk
1146. Send a message in worktree thread → verify agent runs in worktree cwd
1157. Add a non-git project → verify graceful error, can still create thread
AGENTS.md+7
......@@ -1,11 +1,13 @@
11# CLAUDE.md
22
33## Project Snapshot
4
45T3 Code is a minimal web GUI for using code agents like Codex and Claude Code (coming soon).
56
67This repository is a VERY EARLY WIP. Proposing sweeping changes that improve long-term maintainability is encouraged.
78
89## Core Priorities
10
9111. Performance first.
10122. Reliability first.
11133. Keep behavior predictable under load and during failures (session restarts, reconnects, partial streams).
......@@ -13,23 +15,28 @@ This repository is a VERY EARLY WIP. Proposing sweeping changes that improve lon
1315If a tradeoff is required, choose correctness and robustness over short-term convenience.
1416
1517## Package Roles
18
1619- `apps/server`: Node.js WebSocket server. Wraps Codex app-server (JSON-RPC over stdio), serves the React web app, and manages provider sessions.
1720- `apps/web`: React/Vite UI. Owns session UX, conversation/event rendering, and client-side state. Connects to the server via WebSocket.
1821- `packages/contracts`: Shared Zod schemas and TypeScript contracts for provider events, WebSocket protocol, and model/session types.
1922
2023## Codex App Server (Important)
24
2125T3 Code is currently Codex-first. The server starts `codex app-server` (JSON-RPC over stdio) per provider session, then streams structured events to the browser through WebSocket push messages.
2226
2327How we use it in this codebase:
28
2429- Session startup/resume and turn lifecycle are brokered in `apps/server/src/codexAppServerManager.ts`.
2530- Provider dispatch and thread event logging are coordinated in `apps/server/src/providerManager.ts`.
2631- WebSocket server routes NativeApi methods in `apps/server/src/wsServer.ts`.
2732- Web app consumes provider event streams via WebSocket push on channel `providers.event`.
2833
2934Docs:
35
3036- Codex App Server docs: https://developers.openai.com/codex/sdk/#app-server
3137
3238## Reference Repos
39
3340- Open-source Codex repo: https://github.com/openai/codex
3441- Codex-Monitor (Tauri, feature-complete, strong reference implementation): https://github.com/Dimillian/CodexMonitor
3542
README.md+2-2
......@@ -59,8 +59,8 @@ npx t3
5959
6060## Scripts
6161
62- `bun run dev` — Starts contracts, server, and web dev tasks via Turborepo's parallel task runner.
63- `bun run dev:server` — Starts just the WebSocket server (uses tsx for TS execution).
62- `bun run dev` — Starts contracts, server, and web in `turbo watch` mode.
63- `bun run dev:server` — Starts just the WebSocket server (uses Bun TypeScript execution).
6464- `bun run dev:web` — Starts just the Vite dev server for the web app.
6565- `bun run start` — Runs the production server (serves built web app as static files).
6666- `bun run build` — Builds contracts, web app, and server through Turbo.
apps/desktop/package.json+5-6
......@@ -4,10 +4,10 @@
44 "private": true,
55 "main": "dist-electron/main.js",
66 "scripts": {
7 "dev": "bun run --cwd ../server build && concurrently -k -n BUNDLE,WEB,ELECTRON \"bun run dev:bundle\" \"bun run --cwd ../web dev\" \"bun run dev:electron\"",
8 "dev:bundle": "tsup --watch",
7 "dev": "bun run --parallel dev:bundle dev:electron",
8 "dev:bundle": "tsdown --watch",
99 "dev:electron": "bun run scripts/dev-electron.mjs",
10 "build": "tsup",
10 "build": "tsdown",
1111 "start": "electron dist-electron/main.js",
1212 "typecheck": "tsc --noEmit",
1313 "test": "vitest run --passWithNoTests",
......@@ -18,11 +18,10 @@
1818 },
1919 "devDependencies": {
2020 "@types/node": "^22.10.2",
21 "concurrently": "^9.1.2",
2221 "electronmon": "^2.0.2",
23 "tsup": "^8.3.5",
22 "tsdown": "^0.20.3",
2423 "typescript": "^5.7.3",
25 "vitest": "^3.0.0",
24 "vitest": "^4.0.0",
2625 "wait-on": "^8.0.2"
2726 }
2827}
apps/desktop/scripts/dev-electron.mjs+1-1
......@@ -10,7 +10,7 @@ await waitOn({
1010 `tcp:${port}`,
1111 "file:dist-electron/main.js",
1212 "file:dist-electron/preload.js",
13 "file:../server/dist/index.js",
13 "file:../server/dist/index.mjs",
1414 ],
1515});
1616
apps/desktop/scripts/smoke-test.mjs+1-5
......@@ -1,16 +1,12 @@
1import { execSync, spawn } from "node:child_process";
1import { spawn } from "node:child_process";
22import { dirname, resolve } from "node:path";
33import { fileURLToPath } from "node:url";
44
55const __dirname = dirname(fileURLToPath(import.meta.url));
66const desktopDir = resolve(__dirname, "..");
7const rootDir = resolve(__dirname, "../../..");
87const electronBin = resolve(desktopDir, "node_modules/.bin/electron");
98const mainJs = resolve(desktopDir, "dist-electron/main.js");
109
11console.log("Building contracts + web + server + desktop...");
12execSync("bun run build", { cwd: rootDir, stdio: "inherit" });
13
1410console.log("\nLaunching Electron smoke test...");
1511
1612const child = spawn(electronBin, [mainJs], {
apps/desktop/src/main.ts+2-1
......@@ -14,7 +14,7 @@ fixPath();
1414const PICK_FOLDER_CHANNEL = "desktop:pick-folder";
1515const CONTEXT_MENU_CHANNEL = "desktop:context-menu";
1616const ROOT_DIR = path.resolve(__dirname, "../../..");
17const BACKEND_ENTRY = path.join(ROOT_DIR, "apps/server/dist/index.js");
17const BACKEND_ENTRY = path.join(ROOT_DIR, "apps/server/dist/index.mjs");
1818const WEB_ENTRY = path.join(ROOT_DIR, "apps/web/dist/index.html");
1919const STATE_DIR = path.join(os.homedir(), ".t3", "userdata");
2020const isDevelopment = Boolean(process.env.VITE_DEV_SERVER_URL);
......@@ -186,6 +186,7 @@ function createWindow(): BrowserWindow {
186186
187187 if (isDevelopment) {
188188 void window.loadURL(process.env.VITE_DEV_SERVER_URL as string);
189 window.webContents.openDevTools({ mode: "detach" });
189190 } else {
190191 if (!fs.existsSync(WEB_ENTRY)) {
191192 throw new Error(`Web bundle missing at ${WEB_ENTRY}`);
apps/desktop/tsconfig.json+2-2
......@@ -3,7 +3,7 @@
33 "compilerOptions": {
44 "composite": true,
55 "types": ["node", "electron"],
6 "lib": ["ES2023", "DOM"]
6 "lib": ["ES2023", "DOM", "esnext.disposable"]
77 },
8 "include": ["src", "tsup.config.ts"]
8 "include": ["src", "tsdown.config.ts"]
99}
apps/desktop/tsdown.config.ts created+21
......@@ -0,0 +1,21 @@
1import { defineConfig } from "tsdown";
2
3const shared = {
4 format: "cjs" as const,
5 outDir: "dist-electron",
6 sourcemap: true,
7 outExtensions: () => ({ js: ".js" }),
8};
9
10export default defineConfig([
11 {
12 ...shared,
13 entry: ["src/main.ts"],
14 clean: true,
15 noExternal: ["@t3tools/contracts"],
16 },
17 {
18 ...shared,
19 entry: ["src/preload.ts"],
20 },
21]);
apps/desktop/tsup.config.ts deleted-10
......@@ -1,10 +0,0 @@
1import { defineConfig } from "tsup";
2
3export default defineConfig({
4 entry: ["src/main.ts", "src/preload.ts"],
5 format: "cjs",
6 outDir: "dist-electron",
7 sourcemap: true,
8 clean: true,
9 noExternal: ["@t3tools/contracts"],
10});
apps/desktop/turbo.jsonc created+24
......@@ -0,0 +1,24 @@
1{
2 "$schema": "https://turbo.build/schema.json",
3 "extends": ["//"],
4 "tasks": {
5 "build": {
6 "dependsOn": ["^build"],
7 "outputs": ["dist-electron/**"],
8 },
9 "dev": {
10 "dependsOn": ["t3#build"],
11 "persistent": true,
12 },
13 "start": {
14 "dependsOn": ["build", "@t3tools/web#build", "t3#build"],
15 "cache": false,
16 "persistent": true,
17 },
18 "smoke-test": {
19 "dependsOn": ["build", "@t3tools/web#build", "t3#build"],
20 "cache": false,
21 "outputs": [],
22 },
23 },
24}
apps/server/package.json+6-9
......@@ -2,19 +2,17 @@
22 "name": "t3",
33 "version": "0.1.0",
44 "bin": {
5 "t3": "./dist/index.js"
5 "t3": "./dist/index.mjs"
66 },
77 "files": [
88 "dist"
99 ],
1010 "type": "module",
11 "main": "./dist/index.js",
11 "main": "./dist/index.mjs",
1212 "scripts": {
13 "dev": "VITE_DEV_SERVER_URL=http://localhost:5173 tsx src/index.ts",
14 "dev:desktop": "T3CODE_MODE=desktop T3CODE_NO_BROWSER=1 tsx src/index.ts",
15 "build": "tsup && node scripts/bundle-client.mjs",
16 "start": "node dist/index.js",
17 "start:desktop": "T3CODE_MODE=desktop T3CODE_NO_BROWSER=1 node dist/index.js",
13 "dev": "VITE_DEV_SERVER_URL=http://localhost:5173 bun run src/index.ts",
14 "build": "tsdown && node scripts/bundle-client.mjs",
15 "start": "node dist/index.mjs",
1816 "typecheck": "tsc --noEmit",
1917 "test": "vitest run"
2018 },
......@@ -27,8 +25,7 @@
2725 "@t3tools/web": "workspace:*",
2826 "@types/node": "^22.10.2",
2927 "@types/ws": "^8.5.13",
30 "tsup": "^8.3.5",
31 "tsx": "^4.19.0",
28 "tsdown": "^0.20.3",
3229 "typescript": "^5.7.3"
3330 }
3431}
apps/server/src/codexAppServerManager.test.ts+2-6
......@@ -57,17 +57,13 @@ describe("normalizeCodexModelSlug", () => {
5757describe("isRecoverableThreadResumeError", () => {
5858 it("matches not-found resume errors", () => {
5959 expect(
60 isRecoverableThreadResumeError(
61 new Error("thread/resume failed: thread not found"),
62 ),
60 isRecoverableThreadResumeError(new Error("thread/resume failed: thread not found")),
6361 ).toBe(true);
6462 });
6563
6664 it("ignores non-resume errors", () => {
6765 expect(
68 isRecoverableThreadResumeError(
69 new Error("thread/start failed: permission denied"),
70 ),
66 isRecoverableThreadResumeError(new Error("thread/start failed: permission denied")),
7167 ).toBe(false);
7268 });
7369
apps/server/src/codexAppServerManager.ts+11-33
......@@ -26,9 +26,7 @@ interface PendingRequest {
2626interface PendingApprovalRequest {
2727 requestId: string;
2828 jsonRpcId: string | number;
29 method:
30 | "item/commandExecution/requestApproval"
31 | "item/fileChange/requestApproval";
29 method: "item/commandExecution/requestApproval" | "item/fileChange/requestApproval";
3230 requestKind: ProviderRequestKind;
3331 threadId?: string;
3432 turnId?: string;
......@@ -122,16 +120,12 @@ export function classifyCodexStderrLine(rawLine: string): { message: string } |
122120}
123121
124122export function isRecoverableThreadResumeError(error: unknown): boolean {
125 const message = (
126 error instanceof Error ? error.message : String(error)
127 ).toLowerCase();
123 const message = (error instanceof Error ? error.message : String(error)).toLowerCase();
128124 if (!message.includes("thread/resume")) {
129125 return false;
130126 }
131127
132 return RECOVERABLE_THREAD_RESUME_ERROR_SNIPPETS.some((snippet) =>
133 message.includes(snippet),
134 );
128 return RECOVERABLE_THREAD_RESUME_ERROR_SNIPPETS.some((snippet) => message.includes(snippet));
135129}
136130
137131export interface CodexAppServerManagerEvents {
......@@ -209,14 +203,10 @@ export class CodexAppServerManager extends EventEmitter<CodexAppServerManagerEve
209203 if (input.resumeThreadId) {
210204 try {
211205 threadOpenMethod = "thread/resume";
212 threadOpenResponse = await this.sendRequest(
213 context,
214 "thread/resume",
215 {
216 ...sessionOverrides,
217 threadId: input.resumeThreadId,
218 },
219 );
206 threadOpenResponse = await this.sendRequest(context, "thread/resume", {
207 ...sessionOverrides,
208 threadId: input.resumeThreadId,
209 });
220210 } catch (error) {
221211 if (!isRecoverableThreadResumeError(error)) {
222212 throw error;
......@@ -228,19 +218,11 @@ export class CodexAppServerManager extends EventEmitter<CodexAppServerManagerEve
228218 "session/threadResumeFallback",
229219 `Could not resume thread ${input.resumeThreadId}; started a new thread instead.`,
230220 );
231 threadOpenResponse = await this.sendRequest(
232 context,
233 "thread/start",
234 threadStartParams,
235 );
221 threadOpenResponse = await this.sendRequest(context, "thread/start", threadStartParams);
236222 }
237223 } else {
238224 threadOpenMethod = "thread/start";
239 threadOpenResponse = await this.sendRequest(
240 context,
241 "thread/start",
242 threadStartParams,
243 );
225 threadOpenResponse = await this.sendRequest(context, "thread/start", threadStartParams);
244226 }
245227
246228 const threadOpenRecord = this.readObject(threadOpenResponse);
......@@ -248,9 +230,7 @@ export class CodexAppServerManager extends EventEmitter<CodexAppServerManagerEve
248230 this.readString(this.readObject(threadOpenRecord, "thread"), "id") ??
249231 this.readString(threadOpenRecord, "threadId");
250232 if (!threadId) {
251 throw new Error(
252 `${threadOpenMethod} response did not include a thread id.`,
253 );
233 throw new Error(`${threadOpenMethod} response did not include a thread id.`);
254234 }
255235
256236 this.updateSession(context, {
......@@ -732,9 +712,7 @@ export class CodexAppServerManager extends EventEmitter<CodexAppServerManagerEve
732712 };
733713 }
734714
735 private requestKindForMethod(
736 method: string,
737 ): ProviderRequestKind | undefined {
715 private requestKindForMethod(method: string): ProviderRequestKind | undefined {
738716 if (method === "item/commandExecution/requestApproval") {
739717 return "command";
740718 }
apps/server/src/git.test.ts created+423
......@@ -0,0 +1,423 @@
1import { existsSync } from "node:fs";
2import { mkdtemp, rm, writeFile } from "node:fs/promises";
3import { tmpdir } from "node:os";
4import path from "node:path";
5import { describe, expect, it } from "vitest";
6
7import {
8 checkoutGitBranch,
9 createGitBranch,
10 createGitWorktree,
11 initGitRepo,
12 listGitBranches,
13 removeGitWorktree,
14 runTerminalCommand,
15} from "./git";
16
17// ── Helpers ──
18
19/** Run a raw git command for test setup (not under test). */
20async function git(cwd: string, command: string): Promise<string> {
21 const result = await runTerminalCommand({
22 command: `git ${command}`,
23 cwd,
24 timeoutMs: 10_000,
25 });
26 if (result.code !== 0) {
27 throw new Error(`git ${command} failed: ${result.stderr}`);
28 }
29 return result.stdout.trim();
30}
31
32/** Create a disposable temp directory that cleans up automatically. */
33async function makeTmpDir() {
34 const dir = await mkdtemp(path.join(tmpdir(), "git-test-"));
35 return {
36 path: dir,
37 [Symbol.asyncDispose]: async () => {
38 await rm(dir, { recursive: true, force: true });
39 },
40 };
41}
42
43/** Create a repo with an initial commit so branches work. */
44async function initRepoWithCommit(cwd: string): Promise<void> {
45 await initGitRepo({ cwd });
46 await git(cwd, "config user.email 'test@test.com'");
47 await git(cwd, "config user.name 'Test'");
48 await writeFile(path.join(cwd, "README.md"), "# test\n");
49 await git(cwd, "add .");
50 await git(cwd, "commit -m 'initial commit'");
51}
52
53// ── Tests ──
54
55describe("git integration", () => {
56 // ── initGitRepo ──
57
58 describe("initGitRepo", () => {
59 it("creates a valid git repo", async () => {
60 await using tmp = await makeTmpDir();
61 await initGitRepo({ cwd: tmp.path });
62 expect(existsSync(path.join(tmp.path, ".git"))).toBe(true);
63 });
64
65 it("listGitBranches reports isRepo: true after init + commit", async () => {
66 await using tmp = await makeTmpDir();
67 await initRepoWithCommit(tmp.path);
68 const result = await listGitBranches({ cwd: tmp.path });
69 expect(result.isRepo).toBe(true);
70 expect(result.branches.length).toBeGreaterThanOrEqual(1);
71 });
72 });
73
74 // ── listGitBranches ──
75
76 describe("listGitBranches", () => {
77 it("returns isRepo: false for non-git directory", async () => {
78 await using tmp = await makeTmpDir();
79 const result = await listGitBranches({ cwd: tmp.path });
80 expect(result.isRepo).toBe(false);
81 expect(result.branches).toEqual([]);
82 });
83
84 it("returns the current branch with current: true", async () => {
85 await using tmp = await makeTmpDir();
86 await initRepoWithCommit(tmp.path);
87 const result = await listGitBranches({ cwd: tmp.path });
88 const current = result.branches.find((b) => b.current);
89 expect(current).toBeDefined();
90 expect(current!.current).toBe(true);
91 });
92
93 it("sorts current branch first", async () => {
94 await using tmp = await makeTmpDir();
95 await initRepoWithCommit(tmp.path);
96 await createGitBranch({ cwd: tmp.path, branch: "aaa-first-alpha" });
97 await createGitBranch({ cwd: tmp.path, branch: "zzz-last" });
98
99 const result = await listGitBranches({ cwd: tmp.path });
100 expect(result.branches[0]!.current).toBe(true);
101 });
102
103 it("lists multiple branches after creating them", async () => {
104 await using tmp = await makeTmpDir();
105 await initRepoWithCommit(tmp.path);
106 await createGitBranch({ cwd: tmp.path, branch: "feature-a" });
107 await createGitBranch({ cwd: tmp.path, branch: "feature-b" });
108
109 const result = await listGitBranches({ cwd: tmp.path });
110 const names = result.branches.map((b) => b.name);
111 expect(names).toContain("feature-a");
112 expect(names).toContain("feature-b");
113 });
114
115 it("isDefault is false when no remote exists", async () => {
116 await using tmp = await makeTmpDir();
117 await initRepoWithCommit(tmp.path);
118 const result = await listGitBranches({ cwd: tmp.path });
119 expect(result.branches.every((b) => b.isDefault === false)).toBe(true);
120 });
121 });
122
123 // ── checkoutGitBranch ──
124
125 describe("checkoutGitBranch", () => {
126 it("checks out an existing branch", async () => {
127 await using tmp = await makeTmpDir();
128 await initRepoWithCommit(tmp.path);
129 await createGitBranch({ cwd: tmp.path, branch: "feature" });
130
131 await checkoutGitBranch({ cwd: tmp.path, branch: "feature" });
132
133 const result = await listGitBranches({ cwd: tmp.path });
134 const current = result.branches.find((b) => b.current);
135 expect(current!.name).toBe("feature");
136 });
137
138 it("throws when branch does not exist", async () => {
139 await using tmp = await makeTmpDir();
140 await initRepoWithCommit(tmp.path);
141 await expect(checkoutGitBranch({ cwd: tmp.path, branch: "nonexistent" })).rejects.toThrow();
142 });
143
144 it("throws when checkout would overwrite uncommitted changes", async () => {
145 await using tmp = await makeTmpDir();
146 await initRepoWithCommit(tmp.path);
147 await createGitBranch({ cwd: tmp.path, branch: "other" });
148
149 // Create a conflicting change: modify README on current branch
150 await writeFile(path.join(tmp.path, "README.md"), "modified\n");
151 await git(tmp.path, "add README.md");
152
153 // First, checkout other branch cleanly
154 await git(tmp.path, "stash");
155 await checkoutGitBranch({ cwd: tmp.path, branch: "other" });
156 await writeFile(path.join(tmp.path, "README.md"), "other content\n");
157 await git(tmp.path, "add .");
158 await git(tmp.path, "commit -m 'other change'");
159
160 // Go back to default branch
161 const defaultBranch = (await listGitBranches({ cwd: tmp.path })).branches.find(
162 (b) => !b.current,
163 )!.name;
164 await checkoutGitBranch({ cwd: tmp.path, branch: defaultBranch });
165
166 // Make uncommitted changes to the same file
167 await writeFile(path.join(tmp.path, "README.md"), "conflicting local\n");
168
169 // Checkout should fail due to uncommitted changes
170 await expect(checkoutGitBranch({ cwd: tmp.path, branch: "other" })).rejects.toThrow();
171 });
172 });
173
174 // ── createGitBranch ──
175
176 describe("createGitBranch", () => {
177 it("creates a new branch visible in listGitBranches", async () => {
178 await using tmp = await makeTmpDir();
179 await initRepoWithCommit(tmp.path);
180 await createGitBranch({ cwd: tmp.path, branch: "new-feature" });
181
182 const result = await listGitBranches({ cwd: tmp.path });
183 expect(result.branches.some((b) => b.name === "new-feature")).toBe(true);
184 });
185
186 it("throws when branch already exists", async () => {
187 await using tmp = await makeTmpDir();
188 await initRepoWithCommit(tmp.path);
189 await createGitBranch({ cwd: tmp.path, branch: "dupe" });
190 await expect(createGitBranch({ cwd: tmp.path, branch: "dupe" })).rejects.toThrow();
191 });
192 });
193
194 // ── createGitWorktree + removeGitWorktree ──
195
196 describe("createGitWorktree", () => {
197 it("creates a worktree with a new branch from the base branch", async () => {
198 await using tmp = await makeTmpDir();
199 await initRepoWithCommit(tmp.path);
200
201 const wtPath = path.join(tmp.path, "worktree-out");
202 const currentBranch = (await listGitBranches({ cwd: tmp.path })).branches.find(
203 (b) => b.current,
204 )!.name;
205
206 const result = await createGitWorktree({
207 cwd: tmp.path,
208 branch: currentBranch,
209 newBranch: "wt-branch",
210 path: wtPath,
211 });
212
213 expect(result.worktree.path).toBe(wtPath);
214 expect(result.worktree.branch).toBe("wt-branch");
215 expect(existsSync(wtPath)).toBe(true);
216 expect(existsSync(path.join(wtPath, "README.md"))).toBe(true);
217
218 // Clean up worktree before tmp dir disposal
219 await removeGitWorktree({ cwd: tmp.path, path: wtPath });
220 });
221
222 it("worktree has the new branch checked out", async () => {
223 await using tmp = await makeTmpDir();
224 await initRepoWithCommit(tmp.path);
225
226 const wtPath = path.join(tmp.path, "wt-check-dir");
227 const currentBranch = (await listGitBranches({ cwd: tmp.path })).branches.find(
228 (b) => b.current,
229 )!.name;
230
231 await createGitWorktree({
232 cwd: tmp.path,
233 branch: currentBranch,
234 newBranch: "wt-check",
235 path: wtPath,
236 });
237
238 // Verify the worktree is on the new branch
239 const branchOutput = await git(wtPath, "branch --show-current");
240 expect(branchOutput).toBe("wt-check");
241
242 await removeGitWorktree({ cwd: tmp.path, path: wtPath });
243 });
244
245 it("throws when new branch name already exists", async () => {
246 await using tmp = await makeTmpDir();
247 await initRepoWithCommit(tmp.path);
248 await createGitBranch({ cwd: tmp.path, branch: "existing" });
249
250 const wtPath = path.join(tmp.path, "wt-conflict");
251 const currentBranch = (await listGitBranches({ cwd: tmp.path })).branches.find(
252 (b) => b.current,
253 )!.name;
254
255 await expect(
256 createGitWorktree({
257 cwd: tmp.path,
258 branch: currentBranch,
259 newBranch: "existing",
260 path: wtPath,
261 }),
262 ).rejects.toThrow();
263 });
264
265 it("listGitBranches from worktree cwd reports worktree branch as current", async () => {
266 await using tmp = await makeTmpDir();
267 await initRepoWithCommit(tmp.path);
268
269 const wtPath = path.join(tmp.path, "wt-list-dir");
270 const mainBranch = (await listGitBranches({ cwd: tmp.path })).branches.find(
271 (b) => b.current,
272 )!.name;
273
274 await createGitWorktree({
275 cwd: tmp.path,
276 branch: mainBranch,
277 newBranch: "wt-list",
278 path: wtPath,
279 });
280
281 // listGitBranches from the worktree should show wt-list as current
282 const wtBranches = await listGitBranches({ cwd: wtPath });
283 expect(wtBranches.isRepo).toBe(true);
284 const wtCurrent = wtBranches.branches.find((b) => b.current);
285 expect(wtCurrent!.name).toBe("wt-list");
286
287 // Main repo should still show the original branch as current
288 const mainBranches = await listGitBranches({ cwd: tmp.path });
289 const mainCurrent = mainBranches.branches.find((b) => b.current);
290 expect(mainCurrent!.name).toBe(mainBranch);
291
292 await removeGitWorktree({ cwd: tmp.path, path: wtPath });
293 });
294
295 it("removeGitWorktree cleans up the worktree", async () => {
296 await using tmp = await makeTmpDir();
297 await initRepoWithCommit(tmp.path);
298
299 const wtPath = path.join(tmp.path, "wt-remove-dir");
300 const currentBranch = (await listGitBranches({ cwd: tmp.path })).branches.find(
301 (b) => b.current,
302 )!.name;
303
304 await createGitWorktree({
305 cwd: tmp.path,
306 branch: currentBranch,
307 newBranch: "wt-remove",
308 path: wtPath,
309 });
310 expect(existsSync(wtPath)).toBe(true);
311
312 await removeGitWorktree({ cwd: tmp.path, path: wtPath });
313 expect(existsSync(wtPath)).toBe(false);
314 });
315 });
316
317 // ── Full flow: local branch checkout ──
318
319 describe("full flow: local branch checkout", () => {
320 it("init → commit → create branch → checkout → verify current", async () => {
321 await using tmp = await makeTmpDir();
322 await initRepoWithCommit(tmp.path);
323 await createGitBranch({ cwd: tmp.path, branch: "feature-login" });
324 await checkoutGitBranch({ cwd: tmp.path, branch: "feature-login" });
325
326 const result = await listGitBranches({ cwd: tmp.path });
327 const current = result.branches.find((b) => b.current);
328 expect(current!.name).toBe("feature-login");
329 });
330 });
331
332 // ── Full flow: worktree creation from base branch ──
333
334 describe("full flow: worktree creation", () => {
335 it("creates worktree with new branch from current branch", async () => {
336 await using tmp = await makeTmpDir();
337 await initRepoWithCommit(tmp.path);
338
339 const currentBranch = (await listGitBranches({ cwd: tmp.path })).branches.find(
340 (b) => b.current,
341 )!.name;
342
343 const wtPath = path.join(tmp.path, "my-worktree");
344 const result = await createGitWorktree({
345 cwd: tmp.path,
346 branch: currentBranch,
347 newBranch: "feature-wt",
348 path: wtPath,
349 });
350
351 // Worktree exists
352 expect(existsSync(result.worktree.path)).toBe(true);
353
354 // Main repo still on original branch
355 const mainBranches = await listGitBranches({ cwd: tmp.path });
356 const mainCurrent = mainBranches.branches.find((b) => b.current);
357 expect(mainCurrent!.name).toBe(currentBranch);
358
359 // Worktree is on the new branch
360 const wtBranch = await git(wtPath, "branch --show-current");
361 expect(wtBranch).toBe("feature-wt");
362
363 await removeGitWorktree({ cwd: tmp.path, path: wtPath });
364 });
365 });
366
367 // ── Full flow: thread switching simulation ──
368
369 describe("full flow: thread switching (checkout toggling)", () => {
370 it("checkout a → checkout b → checkout a → current matches", async () => {
371 await using tmp = await makeTmpDir();
372 await initRepoWithCommit(tmp.path);
373 await createGitBranch({ cwd: tmp.path, branch: "branch-a" });
374 await createGitBranch({ cwd: tmp.path, branch: "branch-b" });
375
376 // Simulate switching to thread A's branch
377 await checkoutGitBranch({ cwd: tmp.path, branch: "branch-a" });
378 let branches = await listGitBranches({ cwd: tmp.path });
379 expect(branches.branches.find((b) => b.current)!.name).toBe("branch-a");
380
381 // Simulate switching to thread B's branch
382 await checkoutGitBranch({ cwd: tmp.path, branch: "branch-b" });
383 branches = await listGitBranches({ cwd: tmp.path });
384 expect(branches.branches.find((b) => b.current)!.name).toBe("branch-b");
385
386 // Switch back to thread A
387 await checkoutGitBranch({ cwd: tmp.path, branch: "branch-a" });
388 branches = await listGitBranches({ cwd: tmp.path });
389 expect(branches.branches.find((b) => b.current)!.name).toBe("branch-a");
390 });
391 });
392
393 // ── Full flow: checkout conflict ──
394
395 describe("full flow: checkout conflict", () => {
396 it("uncommitted changes prevent checkout to a diverged branch", async () => {
397 await using tmp = await makeTmpDir();
398 await initRepoWithCommit(tmp.path);
399 await createGitBranch({ cwd: tmp.path, branch: "diverged" });
400
401 // Make diverged branch have different file content
402 await checkoutGitBranch({ cwd: tmp.path, branch: "diverged" });
403 await writeFile(path.join(tmp.path, "README.md"), "diverged content\n");
404 await git(tmp.path, "add .");
405 await git(tmp.path, "commit -m 'diverge'");
406
407 // Actually, let's just get back to the initial branch explicitly
408 const allBranches = await listGitBranches({ cwd: tmp.path });
409 const initialBranch = allBranches.branches.find((b) => b.name !== "diverged")!.name;
410 await checkoutGitBranch({ cwd: tmp.path, branch: initialBranch });
411
412 // Make local uncommitted changes to the same file
413 await writeFile(path.join(tmp.path, "README.md"), "local uncommitted\n");
414
415 // Attempt checkout should fail
416 await expect(checkoutGitBranch({ cwd: tmp.path, branch: "diverged" })).rejects.toThrow();
417
418 // Current branch should still be the initial one
419 const result = await listGitBranches({ cwd: tmp.path });
420 expect(result.branches.find((b) => b.current)!.name).toBe(initialBranch);
421 });
422 });
423});
apps/server/src/git.ts created+229
......@@ -0,0 +1,229 @@
1import { spawn } from "node:child_process";
2import fs from "node:fs";
3import os from "node:os";
4import path from "node:path";
5
6import type {
7 GitCheckoutInput,
8 GitCreateBranchInput,
9 GitCreateWorktreeInput,
10 GitCreateWorktreeResult,
11 GitInitInput,
12 GitListBranchesInput,
13 GitListBranchesResult,
14 GitRemoveWorktreeInput,
15 TerminalCommandInput,
16 TerminalCommandResult,
17} from "@t3tools/contracts";
18
19/** Spawn git directly with an argv array — no shell, no quoting needed. */
20function runGit(args: string[], cwd: string, timeoutMs = 30_000): Promise<TerminalCommandResult> {
21 return new Promise((resolve, reject) => {
22 const child = spawn("git", args, {
23 cwd,
24 env: process.env,
25 stdio: ["ignore", "pipe", "pipe"],
26 });
27
28 let stdout = "";
29 let stderr = "";
30 let timedOut = false;
31
32 const timeout = setTimeout(() => {
33 timedOut = true;
34 child.kill("SIGTERM");
35 setTimeout(() => {
36 if (!child.killed) child.kill("SIGKILL");
37 }, 1_000).unref();
38 }, timeoutMs);
39
40 child.stdout?.on("data", (chunk: Buffer) => {
41 stdout += chunk.toString();
42 });
43 child.stderr?.on("data", (chunk: Buffer) => {
44 stderr += chunk.toString();
45 });
46 child.on("error", (error) => {
47 clearTimeout(timeout);
48 reject(error);
49 });
50 child.on("close", (code, signal) => {
51 clearTimeout(timeout);
52 resolve({ stdout, stderr, code: code ?? null, signal: signal ?? null, timedOut });
53 });
54 });
55}
56
57export async function runTerminalCommand(
58 input: TerminalCommandInput,
59): Promise<TerminalCommandResult> {
60 const shellPath =
61 process.platform === "win32"
62 ? (process.env.ComSpec ?? "cmd.exe")
63 : (process.env.SHELL ?? "/bin/sh");
64
65 const args =
66 process.platform === "win32" ? ["/d", "/s", "/c", input.command] : ["-lc", input.command];
67
68 return new Promise((resolve, reject) => {
69 const child = spawn(shellPath, args, {
70 cwd: input.cwd,
71 env: process.env,
72 stdio: ["ignore", "pipe", "pipe"],
73 });
74
75 let stdout = "";
76 let stderr = "";
77 let timedOut = false;
78
79 const timeout = setTimeout(() => {
80 timedOut = true;
81 child.kill("SIGTERM");
82 setTimeout(() => {
83 if (!child.killed) {
84 child.kill("SIGKILL");
85 }
86 }, 1_000).unref();
87 }, input.timeoutMs ?? 30_000);
88
89 child.stdout?.on("data", (chunk: Buffer) => {
90 stdout += chunk.toString();
91 });
92
93 child.stderr?.on("data", (chunk: Buffer) => {
94 stderr += chunk.toString();
95 });
96
97 child.on("error", (error) => {
98 clearTimeout(timeout);
99 reject(error);
100 });
101
102 child.on("close", (code, signal) => {
103 clearTimeout(timeout);
104 resolve({
105 stdout,
106 stderr,
107 code: code ?? null,
108 signal: signal ?? null,
109 timedOut,
110 });
111 });
112 });
113}
114
115export async function listGitBranches(input: GitListBranchesInput): Promise<GitListBranchesResult> {
116 const result = await runGit(["branch", "--no-color"], input.cwd, 10_000);
117
118 if (result.code !== 0) {
119 const stderr = result.stderr.trim();
120 if (stderr.includes("not a git repository")) {
121 return { branches: [], isRepo: false };
122 }
123 throw new Error(stderr || "git branch failed");
124 }
125
126 // Resolve the real default branch from the remote
127 const [defaultRef, worktreeList] = await Promise.all([
128 runGit(["symbolic-ref", "refs/remotes/origin/HEAD"], input.cwd, 5_000),
129 runGit(["worktree", "list", "--porcelain"], input.cwd, 5_000),
130 ]);
131 const defaultBranch =
132 defaultRef.code === 0 ? defaultRef.stdout.trim().replace(/^refs\/remotes\/origin\//, "") : null;
133
134 // Build branch-name → worktree-path map from porcelain output.
135 // Only include worktrees whose directories still exist on disk (skip prunable/stale ones).
136 const worktreeMap = new Map<string, string>();
137 if (worktreeList.code === 0) {
138 let currentPath: string | null = null;
139 for (const line of worktreeList.stdout.split("\n")) {
140 if (line.startsWith("worktree ")) {
141 currentPath = line.slice("worktree ".length);
142 if (!fs.existsSync(currentPath)) currentPath = null;
143 } else if (line.startsWith("branch refs/heads/") && currentPath) {
144 worktreeMap.set(line.slice("branch refs/heads/".length), currentPath);
145 } else if (line === "") {
146 currentPath = null;
147 }
148 }
149 }
150
151 const branches = result.stdout
152 .split("\n")
153 .map((line) => line.trim())
154 .filter((line) => line.length > 0)
155 .map((line) => {
156 const name = line.replace(/^[*+]\s+/, "");
157 return {
158 name,
159 current: line.startsWith("* "),
160 isDefault: name === defaultBranch,
161 worktreePath: worktreeMap.get(name) ?? null,
162 };
163 })
164 .toSorted((a, b) => {
165 if (a.current !== b.current) return a.current ? -1 : 1;
166 if (a.isDefault !== b.isDefault) return a.isDefault ? -1 : 1;
167 return a.name.localeCompare(b.name);
168 });
169
170 return { branches, isRepo: true };
171}
172
173export async function createGitWorktree(
174 input: GitCreateWorktreeInput,
175): Promise<GitCreateWorktreeResult> {
176 const sanitizedBranch = input.newBranch.replace(/\//g, "-");
177 const repoName = path.basename(input.cwd);
178 const worktreePath =
179 input.path ?? path.join(os.homedir(), ".t3", "worktrees", repoName, sanitizedBranch);
180
181 // Create a new branch from the base branch in a new worktree
182 const result = await runGit(
183 ["worktree", "add", "-b", input.newBranch, worktreePath, input.branch],
184 input.cwd,
185 );
186
187 if (result.code !== 0) {
188 throw new Error(result.stderr.trim() || "git worktree add failed");
189 }
190
191 return {
192 worktree: {
193 path: worktreePath,
194 branch: input.newBranch,
195 },
196 };
197}
198
199export async function removeGitWorktree(input: GitRemoveWorktreeInput): Promise<void> {
200 const result = await runGit(["worktree", "remove", input.path], input.cwd, 15_000);
201
202 if (result.code !== 0) {
203 throw new Error(result.stderr.trim() || "git worktree remove failed");
204 }
205}
206
207export async function createGitBranch(input: GitCreateBranchInput): Promise<void> {
208 const result = await runGit(["branch", input.branch], input.cwd, 10_000);
209
210 if (result.code !== 0) {
211 throw new Error(result.stderr.trim() || "git branch create failed");
212 }
213}
214
215export async function checkoutGitBranch(input: GitCheckoutInput): Promise<void> {
216 const result = await runGit(["checkout", input.branch], input.cwd, 10_000);
217
218 if (result.code !== 0) {
219 throw new Error(result.stderr.trim() || "git checkout failed");
220 }
221}
222
223export async function initGitRepo(input: GitInitInput): Promise<void> {
224 const result = await runGit(["init"], input.cwd, 10_000);
225
226 if (result.code !== 0) {
227 throw new Error(result.stderr.trim() || "git init failed");
228 }
229}
apps/server/src/providerManager.test.ts+1-4
......@@ -16,10 +16,7 @@ describe("ProviderManager", () => {
1616 method: string;
1717 threadId: string;
1818 }) => void;
19 threadLogStreams: Map<
20 string,
21 { writableEnded: boolean; destroyed: boolean }
22 >;
19 threadLogStreams: Map<string, { writableEnded: boolean; destroyed: boolean }>;
2320 };
2421 internals.onCodexEvent({
2522 id: "evt-1",
apps/server/src/providerManager.ts+2-9
......@@ -87,11 +87,7 @@ export class ProviderManager extends EventEmitter<ProviderManagerEvents> {
8787 throw new Error(`Unknown provider session: ${input.sessionId}`);
8888 }
8989
90 await this.codex.respondToRequest(
91 input.sessionId,
92 input.requestId,
93 input.decision,
94 );
90 await this.codex.respondToRequest(input.sessionId, input.requestId, input.decision);
9591 }
9692
9793 stopSession(raw: ProviderStopSessionInput): void {
......@@ -151,10 +147,7 @@ export class ProviderManager extends EventEmitter<ProviderManagerEvents> {
151147
152148 private resolveThreadId(event: ProviderEvent): string | undefined {
153149 const fromPayload = this.readThreadIdFromPayload(event.payload);
154 const threadId =
155 event.threadId ??
156 fromPayload ??
157 this.sessionThreadIds.get(event.sessionId);
150 const threadId = event.threadId ?? fromPayload ?? this.sessionThreadIds.get(event.sessionId);
158151
159152 if (threadId) {
160153 this.sessionThreadIds.set(event.sessionId, threadId);
apps/server/src/wsServer.test.ts+26
......@@ -281,6 +281,32 @@ describe("WebSocket Server", () => {
281281 expect(afterRemove.result).toEqual([]);
282282 });
283283
284 it("supports git methods over websocket", async () => {
285 const repoCwd = makeTempDir("t3code-ws-git-project-");
286
287 server = createTestServer({ cwd: "/test" });
288 await server.start();
289 const addr = server.httpServer.address();
290 const port = typeof addr === "object" && addr !== null ? addr.port : 0;
291
292 const ws = await connectWs(port);
293 connections.push(ws);
294 await waitForMessage(ws);
295
296 const beforeInit = await sendRequest(ws, WS_METHODS.gitListBranches, { cwd: repoCwd });
297 expect(beforeInit.error).toBeUndefined();
298 expect(beforeInit.result).toEqual({ branches: [], isRepo: false });
299
300 const initResponse = await sendRequest(ws, WS_METHODS.gitInit, { cwd: repoCwd });
301 expect(initResponse.error).toBeUndefined();
302
303 const afterInit = await sendRequest(ws, WS_METHODS.gitListBranches, {
304 cwd: repoCwd,
305 });
306 expect(afterInit.error).toBeUndefined();
307 expect((afterInit.result as { isRepo: boolean }).isRepo).toBe(true);
308 });
309
284310 it("prunes missing projects on startup", async () => {
285311 const stateDir = makeTempDir("t3code-ws-prune-state-");
286312 const existing = makeTempDir("t3code-ws-existing-project-");
apps/server/src/wsServer.ts+30-1
......@@ -19,6 +19,14 @@ import { WebSocketServer, type WebSocket } from "ws";
1919import { createLogger } from "./logger";
2020import { ProjectRegistry } from "./projectRegistry";
2121import { ProviderManager } from "./providerManager";
22import {
23 checkoutGitBranch,
24 createGitBranch,
25 createGitWorktree,
26 initGitRepo,
27 listGitBranches,
28 removeGitWorktree,
29} from "./git";
2230
2331const MIME_TYPES: Record<string, string> = {
2432 ".html": "text/html; charset=utf-8",
......@@ -304,6 +312,24 @@ export function createServer(options: ServerOptions) {
304312 return undefined;
305313 }
306314
315 case WS_METHODS.gitListBranches:
316 return listGitBranches(request.params as never);
317
318 case WS_METHODS.gitCreateWorktree:
319 return createGitWorktree(request.params as never);
320
321 case WS_METHODS.gitRemoveWorktree:
322 return removeGitWorktree(request.params as never);
323
324 case WS_METHODS.gitCreateBranch:
325 return createGitBranch(request.params as never);
326
327 case WS_METHODS.gitCheckout:
328 return checkoutGitBranch(request.params as never);
329
330 case WS_METHODS.gitInit:
331 return initGitRepo(request.params as never);
332
307333 case WS_METHODS.serverGetConfig:
308334 return { cwd };
309335
......@@ -343,7 +369,10 @@ export function createServer(options: ServerOptions) {
343369 const isServerNotRunningError = (error: unknown): boolean => {
344370 if (!(error instanceof Error)) return false;
345371 const maybeCode = (error as NodeJS.ErrnoException).code;
346 return maybeCode === "ERR_SERVER_NOT_RUNNING" || error.message.toLowerCase().includes("not running");
372 return (
373 maybeCode === "ERR_SERVER_NOT_RUNNING" ||
374 error.message.toLowerCase().includes("not running")
375 );
347376 };
348377
349378 const closeWebSocketServer = new Promise<void>((resolve, reject) => {
apps/server/tsconfig.json+2-2
......@@ -3,7 +3,7 @@
33 "compilerOptions": {
44 "composite": true,
55 "types": ["node"],
6 "lib": ["ES2023"]
6 "lib": ["ES2023", "esnext.disposable"]
77 },
8 "include": ["src", "tsup.config.ts"]
8 "include": ["src", "tsdown.config.ts"]
99}
apps/server/tsdown.config.ts created+14
......@@ -0,0 +1,14 @@
1import { defineConfig } from "tsdown";
2
3export default defineConfig({
4 entry: ["src/index.ts"],
5 format: ["esm", "cjs"],
6 outDir: "dist",
7 sourcemap: true,
8 clean: true,
9 noExternal: ["@t3tools/contracts", "zod"],
10 inlineOnly: false,
11 banner: {
12 js: "#!/usr/bin/env node\n",
13 },
14});
apps/server/tsup.config.ts deleted-13
......@@ -1,13 +0,0 @@
1import { defineConfig } from "tsup";
2
3export default defineConfig({
4 entry: ["src/index.ts"],
5 format: "esm",
6 outDir: "dist",
7 sourcemap: true,
8 clean: true,
9 noExternal: ["@t3tools/contracts"],
10 banner: {
11 js: '#!/usr/bin/env node\n',
12 },
13});
apps/server/turbo.jsonc created+11
......@@ -0,0 +1,11 @@
1{
2 "$schema": "https://turbo.build/schema.json",
3 "extends": ["//"],
4 "tasks": {
5 "start": {
6 "dependsOn": ["build"],
7 "cache": false,
8 "persistent": true,
9 },
10 },
11}
apps/web/index.html+4-1
......@@ -5,7 +5,10 @@
55 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
66 <link rel="preconnect" href="https://fonts.googleapis.com" />
77 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
8 <link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,300..800;1,9..40,300..800&display=swap" rel="stylesheet" />
8 <link
9 href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,300..800;1,9..40,300..800&display=swap"
10 rel="stylesheet"
11 />
912 <title>T3 Code</title>
1013 </head>
1114 <body>
apps/web/package.json+3-2
......@@ -12,6 +12,7 @@
1212 },
1313 "dependencies": {
1414 "@t3tools/contracts": "workspace:*",
15 "@tanstack/react-query": "^5.90.0",
1516 "highlight.js": "^11.11.1",
1617 "lucide-react": "^0.563.0",
1718 "react": "^19.0.0",
......@@ -25,10 +26,10 @@
2526 "@tailwindcss/vite": "^4.0.0",
2627 "@types/react": "^19.0.0",
2728 "@types/react-dom": "^19.0.0",
28 "@vitejs/plugin-react": "^4.3.4",
29 "@vitejs/plugin-react": "^5.1.4",
2930 "babel-plugin-react-compiler": "^19.0.0-beta-e552027-20250112",
3031 "tailwindcss": "^4.0.0",
3132 "typescript": "^5.7.3",
32 "vite": "^6.0.5"
33 "vite": "^8.0.0-beta.12"
3334 }
3435}
apps/web/src/App.tsx+10-3
......@@ -1,3 +1,4 @@
1import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
12import { useEffect, useMemo, useRef } from "react";
23
34import ChatView from "./components/ChatView";
......@@ -82,6 +83,8 @@ function AutoProjectBootstrap() {
8283 events: [],
8384 error: null,
8485 createdAt: new Date().toISOString(),
86 branch: null,
87 worktreePath: null,
8588 },
8689 });
8790 });
......@@ -166,10 +169,14 @@ function Layout() {
166169 );
167170}
168171
172const queryClient = new QueryClient();
173
169174export default function App() {
170175 return (
171 <StoreProvider>
172 <Layout />
173 </StoreProvider>
176 <QueryClientProvider client={queryClient}>
177 <StoreProvider>
178 <Layout />
179 </StoreProvider>
180 </QueryClientProvider>
174181 );
175182}
apps/web/src/components/BranchToolbar.tsx created+315
......@@ -0,0 +1,315 @@
1import type { GitBranch } from "@t3tools/contracts";
2import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
3import { useEffect, useMemo, useRef, useState } from "react";
4
5import { readNativeApi } from "../session-logic";
6import { useStore } from "../store";
7
8interface BranchToolbarProps {
9 envMode: "local" | "worktree";
10 onEnvModeChange: (mode: "local" | "worktree") => void;
11 envLocked: boolean;
12}
13
14export default function BranchToolbar({ envMode, onEnvModeChange, envLocked }: BranchToolbarProps) {
15 const { state, dispatch } = useStore();
16 const api = useMemo(() => readNativeApi(), []);
17 const queryClient = useQueryClient();
18
19 const [isBranchMenuOpen, setIsBranchMenuOpen] = useState(false);
20 const [isCreatingBranch, setIsCreatingBranch] = useState(false);
21 const [newBranchName, setNewBranchName] = useState("");
22 const branchMenuRef = useRef<HTMLDivElement>(null);
23
24 const activeThread = state.threads.find((thread) => thread.id === state.activeThreadId);
25 const activeProject = state.projects.find((project) => project.id === activeThread?.projectId);
26 const activeThreadId = activeThread?.id;
27 const activeThreadBranch = activeThread?.branch ?? null;
28 const activeWorktreePath = activeThread?.worktreePath ?? null;
29 const branchCwd = activeWorktreePath ?? activeProject?.cwd;
30
31 // ── Queries ───────────────────────────────────────────────────────────
32
33 const branchesQuery = useQuery({
34 queryKey: ["git", "branches", branchCwd],
35 queryFn: () => api!.git.listBranches({ cwd: branchCwd! }),
36 enabled: !!api && !!branchCwd,
37 });
38
39 const branches = branchesQuery.data?.branches ?? [];
40 // Default to true while loading — showing "Initialize git" during a fetch is wrong,
41 // and worktrees are inherently git repos.
42 const isRepo = branchesQuery.data?.isRepo ?? !branchesQuery.isLoading;
43
44 // ── Mutations ─────────────────────────────────────────────────────────
45
46 const checkoutMutation = useMutation({
47 mutationFn: (branch: string) => api!.git.checkout({ cwd: branchCwd!, branch }),
48 onSuccess: () => queryClient.invalidateQueries({ queryKey: ["git", "branches", branchCwd] }),
49 onError: (error) =>
50 setThreadError(error instanceof Error ? error.message : "Failed to checkout branch."),
51 });
52
53 const createBranchMutation = useMutation({
54 mutationFn: (branch: string) =>
55 api!.git
56 .createBranch({ cwd: branchCwd!, branch })
57 .then(() => api!.git.checkout({ cwd: branchCwd!, branch })),
58 onSuccess: () => queryClient.invalidateQueries({ queryKey: ["git", "branches", branchCwd] }),
59 onError: (error) =>
60 setThreadError(error instanceof Error ? error.message : "Failed to create branch."),
61 });
62
63 const initMutation = useMutation({
64 mutationFn: () => api!.git.init({ cwd: branchCwd! }),
65 onSuccess: () => {
66 setThreadError(null);
67 queryClient.invalidateQueries({ queryKey: ["git", "branches", branchCwd] });
68 },
69 onError: (error) =>
70 setThreadError(error instanceof Error ? error.message : "Failed to initialize git repo."),
71 });
72
73 // ── Effects ───────────────────────────────────────────────────────────
74
75 // Keep thread branch synced to git current branch for local threads.
76 const queryBranches = branchesQuery.data?.branches;
77 useEffect(() => {
78 if (!activeThreadId || activeWorktreePath) return;
79 const current = queryBranches?.find((branch) => branch.current);
80 if (!current) return;
81 if (current.name === activeThreadBranch) return;
82 dispatch({
83 type: "SET_THREAD_BRANCH",
84 threadId: activeThreadId,
85 branch: current.name,
86 worktreePath: null,
87 });
88 }, [activeThreadId, activeWorktreePath, activeThreadBranch, queryBranches, dispatch]);
89
90 useEffect(() => {
91 if (!isBranchMenuOpen) return;
92 const handleClickOutside = (event: MouseEvent) => {
93 if (!branchMenuRef.current) return;
94 if (event.target instanceof Node && !branchMenuRef.current.contains(event.target)) {
95 setIsBranchMenuOpen(false);
96 }
97 };
98 window.addEventListener("mousedown", handleClickOutside);
99 return () => {
100 window.removeEventListener("mousedown", handleClickOutside);
101 };
102 }, [isBranchMenuOpen]);
103
104 // ── Helpers ───────────────────────────────────────────────────────────
105
106 const setThreadError = (error: string | null) => {
107 if (!activeThreadId) return;
108 dispatch({ type: "SET_ERROR", threadId: activeThreadId, error });
109 };
110
111 const setThreadBranch = (branch: string | null, worktreePath: string | null) => {
112 if (!activeThreadId) return;
113 // If the effective cwd is about to change, stop the running session so the
114 // next message creates a new one with the correct cwd.
115 const sessionId = activeThread?.session?.sessionId;
116 if (sessionId && worktreePath !== activeWorktreePath) {
117 void api?.providers.stopSession({ sessionId }).catch(() => undefined);
118 }
119 dispatch({ type: "SET_THREAD_BRANCH", threadId: activeThreadId, branch, worktreePath });
120 };
121
122 const selectBranch = (branch: GitBranch) => {
123 if (!api || !activeThreadId || !branchCwd) return;
124
125 // For new worktree mode, selecting a branch picks the base branch.
126 if (envMode === "worktree" && !envLocked && !activeWorktreePath) {
127 setThreadError(null);
128 setThreadBranch(branch.name, null);
129 setIsBranchMenuOpen(false);
130 return;
131 }
132
133 // If the branch already lives in a worktree, redirect there instead of
134 // trying to checkout (which git would reject with "already used by worktree").
135 if (branch.worktreePath) {
136 const isMainWorktree = branch.worktreePath === activeProject?.cwd;
137 setThreadError(null);
138 // Main worktree → switch back to local (project cwd, worktreePath=null).
139 // Secondary worktree → point the thread at that worktree path.
140 setThreadBranch(branch.name, isMainWorktree ? null : branch.worktreePath);
141 setIsBranchMenuOpen(false);
142 return;
143 }
144
145 checkoutMutation.mutate(branch.name, {
146 onSuccess: () => {
147 setThreadError(null);
148 setThreadBranch(branch.name, activeWorktreePath);
149 setIsBranchMenuOpen(false);
150 },
151 });
152 };
153
154 const createBranch = () => {
155 const name = newBranchName.trim();
156 if (!api || !activeThreadId || !branchCwd || !name) return;
157 createBranchMutation.mutate(name, {
158 onSuccess: () => {
159 setThreadError(null);
160 setThreadBranch(name, activeWorktreePath);
161 setNewBranchName("");
162 setIsCreatingBranch(false);
163 setIsBranchMenuOpen(false);
164 },
165 });
166 };
167
168 if (!activeThread || !activeProject) return null;
169
170 return (
171 <div className="mx-auto flex w-full max-w-3xl items-center justify-between px-5 pb-3 pt-1">
172 <div className="flex items-center gap-2">
173 {envLocked || activeWorktreePath ? (
174 <span className="inline-flex items-center gap-1.5 px-1 text-[12px] text-muted-foreground/55">
175 {activeWorktreePath ? "Worktree" : "Local"}
176 </span>
177 ) : (
178 <button
179 type="button"
180 className={`inline-flex items-center gap-1.5 rounded-lg px-2 py-1 text-[12px] transition-colors duration-150 ${
181 envMode === "worktree"
182 ? "bg-accent text-foreground/80"
183 : "text-muted-foreground/60 hover:bg-accent/50 hover:text-muted-foreground/80"
184 }`}
185 onClick={() => onEnvModeChange(envMode === "local" ? "worktree" : "local")}
186 >
187 {envMode === "worktree" ? "New worktree" : "Local"}
188 </button>
189 )}
190 </div>
191
192 {!isRepo ? (
193 <button
194 type="button"
195 className="inline-flex items-center gap-1.5 rounded-lg border border-border px-2 py-1 text-[12px] text-muted-foreground/70 transition-colors duration-150 hover:bg-accent hover:text-foreground/80 disabled:cursor-not-allowed disabled:opacity-50"
196 disabled={!branchCwd || initMutation.isPending}
197 onClick={() => initMutation.mutate()}
198 >
199 {initMutation.isPending ? "Initializing\u2026" : "Initialize git"}
200 </button>
201 ) : (
202 <div className="relative" ref={branchMenuRef}>
203 <button
204 type="button"
205 className="inline-flex items-center gap-1.5 rounded-lg px-2 py-1 text-[12px] text-muted-foreground/60 transition-colors duration-150 hover:bg-accent/50 hover:text-muted-foreground/80"
206 onClick={() => setIsBranchMenuOpen((open) => !open)}
207 disabled={branchesQuery.isLoading}
208 >
209 <span className="max-w-[240px] truncate font-mono">
210 {activeThread.branch
211 ? envMode === "worktree" && !activeWorktreePath
212 ? `From ${activeThread.branch}`
213 : activeThread.branch
214 : "Select branch"}
215 </span>
216 <svg
217 width="10"
218 height="10"
219 viewBox="0 0 10 10"
220 fill="none"
221 className="opacity-40"
222 aria-hidden="true"
223 >
224 <path
225 d="M2.5 4L5 6.5L7.5 4"
226 stroke="currentColor"
227 strokeWidth="1.2"
228 strokeLinecap="round"
229 strokeLinejoin="round"
230 />
231 </svg>
232 </button>
233 {isBranchMenuOpen && (
234 <div className="absolute bottom-full right-0 z-20 mb-2 w-[320px] rounded-2xl border border-border bg-popover/95 p-2 shadow-[0_16px_40px_rgba(0,0,0,0.55)] backdrop-blur">
235 <p className="px-2 py-1 text-[10px] font-medium uppercase tracking-wider text-muted-foreground/55">
236 Branch
237 </p>
238 <div className="max-h-64 overflow-y-auto">
239 {branches.map((branch) => {
240 const isSelected = branch.name === activeThread.branch;
241 const hasSecondaryWorktree =
242 branch.worktreePath && branch.worktreePath !== activeProject.cwd;
243 return (
244 <button
245 key={branch.name}
246 type="button"
247 className={`mb-0.5 flex w-full items-center justify-between gap-2 rounded-xl px-2 py-1.5 text-left font-mono text-xs transition-colors duration-150 ${
248 isSelected
249 ? "bg-accent text-foreground"
250 : "text-foreground/90 hover:bg-accent/50"
251 }`}
252 onClick={() => selectBranch(branch)}
253 >
254 <span className="truncate">{branch.name}</span>
255 {(branch.current || branch.isDefault || hasSecondaryWorktree) && (
256 <span className="shrink-0 text-[10px] text-muted-foreground/45">
257 {branch.current ? "current" : hasSecondaryWorktree ? "worktree" : "default"}
258 </span>
259 )}
260 </button>
261 );
262 })}
263 </div>
264 {envMode === "local" && (
265 <>
266 <div className="mx-1 my-1 h-px bg-border" />
267 {isCreatingBranch ? (
268 <form
269 className="flex items-center gap-1 px-1"
270 onSubmit={(event) => {
271 event.preventDefault();
272 createBranch();
273 }}
274 >
275 <input
276 type="text"
277 className="flex-1 rounded-lg border border-border bg-background px-2 py-1.5 font-mono text-xs text-foreground placeholder:text-muted-foreground/30 focus:border-ring focus:outline-none"
278 placeholder="branch-name"
279 value={newBranchName}
280 onChange={(event) => setNewBranchName(event.target.value)}
281 onKeyDown={(event) => {
282 if (event.key === "Escape") {
283 setIsCreatingBranch(false);
284 setNewBranchName("");
285 }
286 }}
287 // biome-ignore lint/a11y/noAutofocus: branch name input should focus when shown
288 autoFocus
289 />
290 <button
291 type="submit"
292 disabled={!newBranchName.trim() || createBranchMutation.isPending}
293 className="rounded-lg px-2 py-1.5 text-xs text-muted-foreground/70 transition-colors hover:bg-accent hover:text-foreground/80 disabled:opacity-30"
294 >
295 Create
296 </button>
297 </form>
298 ) : (
299 <button
300 type="button"
301 className="w-full rounded-lg px-2 py-1.5 text-left text-xs text-muted-foreground/70 transition-colors duration-150 hover:bg-accent hover:text-foreground/80"
302 onClick={() => setIsCreatingBranch(true)}
303 >
304 + New branch
305 </button>
306 )}
307 </>
308 )}
309 </div>
310 )}
311 </div>
312 )}
313 </div>
314 );
315}
apps/web/src/components/ChatView.tsx+110-134
......@@ -33,6 +33,7 @@ import {
3333 readNativeApi,
3434} from "../session-logic";
3535import { useStore } from "../store";
36import BranchToolbar from "./BranchToolbar";
3637import ChatMarkdown from "./ChatMarkdown";
3738
3839function formatMessageMeta(createdAt: string, duration: string | null): string {
......@@ -91,23 +92,17 @@ function approvalDetail(event: ProviderEvent): string | undefined {
9192 return asString(payload?.reason);
9293}
9394
94function derivePendingApprovals(
95 events: ProviderEvent[],
96): PendingApprovalCard[] {
95function derivePendingApprovals(events: ProviderEvent[]): PendingApprovalCard[] {
9796 const pending = new Map<string, PendingApprovalCard>();
9897 const ordered = [...events].toReversed();
9998
10099 for (const event of ordered) {
101 if (
102 event.method === "session/closed" ||
103 event.method === "session/exited"
104 ) {
100 if (event.method === "session/closed" || event.method === "session/exited") {
105101 pending.clear();
106102 continue;
107103 }
108104
109 const requestId =
110 event.requestId ?? asString(asRecord(event.payload)?.requestId);
105 const requestId = event.requestId ?? asString(asRecord(event.payload)?.requestId);
111106 if (!requestId) continue;
112107
113108 if (
......@@ -142,19 +137,13 @@ export default function ChatView() {
142137 const [isEditorMenuOpen, setIsEditorMenuOpen] = useState(false);
143138 const [lastEditor, setLastEditor] = useState<EditorId>(() => {
144139 const stored = localStorage.getItem(LAST_EDITOR_KEY);
145 return EDITORS.some((e) => e.id === stored)
146 ? (stored as EditorId)
147 : EDITORS[0].id;
140 return EDITORS.some((e) => e.id === stored) ? (stored as EditorId) : EDITORS[0].id;
148141 });
149 const [selectedEffort, setSelectedEffort] =
150 useState<string>(DEFAULT_REASONING);
142 const [selectedEffort, setSelectedEffort] = useState<string>(DEFAULT_REASONING);
143 const [envMode, setEnvMode] = useState<"local" | "worktree">("local");
151144 const [isSwitchingRuntimeMode, setIsSwitchingRuntimeMode] = useState(false);
152 const [respondingRequestIds, setRespondingRequestIds] = useState<string[]>(
153 [],
154 );
155 const [expandedWorkGroups, setExpandedWorkGroups] = useState<
156 Record<string, boolean>
157 >({});
145 const [respondingRequestIds, setRespondingRequestIds] = useState<string[]>([]);
146 const [expandedWorkGroups, setExpandedWorkGroups] = useState<Record<string, boolean>>({});
158147 const [nowTick, setNowTick] = useState(() => Date.now());
159148 const messagesEndRef = useRef<HTMLDivElement>(null);
160149 const textareaRef = useRef<HTMLTextAreaElement>(null);
......@@ -175,11 +164,7 @@ export default function ChatView() {
175164 [activeThread?.events],
176165 );
177166 const latestTurnWorkEntries = useMemo(
178 () =>
179 deriveWorkLogEntries(
180 activeThread?.events ?? [],
181 activeThread?.latestTurnId,
182 ),
167 () => deriveWorkLogEntries(activeThread?.events ?? [], activeThread?.latestTurnId),
183168 [activeThread?.events, activeThread?.latestTurnId],
184169 );
185170 const pendingApprovals = useMemo(
......@@ -265,19 +250,20 @@ export default function ChatView() {
265250 approvalPolicy: "on-request",
266251 sandboxMode: "workspace-write",
267252 } as const);
253 const envLocked = Boolean(
254 activeThread &&
255 (activeThread.messages.length > 0 ||
256 (activeThread.session !== null && activeThread.session.status !== "closed")),
257 );
268258
269 const handleRuntimeModeChange = async (
270 mode: "approval-required" | "full-access",
271 ) => {
259 const handleRuntimeModeChange = async (mode: "approval-required" | "full-access") => {
272260 if (mode === state.runtimeMode) return;
273261 dispatch({ type: "SET_RUNTIME_MODE", mode });
274262 if (!api) return;
275263
276264 const sessionIds = state.threads
277265 .map((t) => t.session)
278 .filter(
279 (s): s is NonNullable<typeof s> => s !== null && s.status !== "closed",
280 )
266 .filter((s): s is NonNullable<typeof s> => s !== null && s.status !== "closed")
281267 .map((s) => s.sessionId);
282268
283269 if (sessionIds.length === 0) return;
......@@ -285,9 +271,7 @@ export default function ChatView() {
285271 setIsSwitchingRuntimeMode(true);
286272 try {
287273 await Promise.all(
288 sessionIds.map((id) =>
289 api.providers.stopSession({ sessionId: id }).catch(() => undefined),
290 ),
274 sessionIds.map((id) => api.providers.stopSession({ sessionId: id }).catch(() => undefined)),
291275 );
292276 } finally {
293277 setIsSwitchingRuntimeMode(false);
......@@ -309,6 +293,12 @@ export default function ChatView() {
309293 setExpandedWorkGroups({});
310294 }, [activeThread?.id]);
311295
296 const activeWorktreePath = activeThread?.worktreePath;
297 useEffect(() => {
298 if (!activeThread?.id) return;
299 setEnvMode(activeWorktreePath ? "worktree" : "local");
300 }, [activeThread?.id, activeWorktreePath]);
301
312302 // Auto-resize textarea
313303 useEffect(() => {
314304 const ta = textareaRef.current;
......@@ -348,10 +338,7 @@ export default function ChatView() {
348338
349339 const handleClickOutside = (event: MouseEvent) => {
350340 if (!editorMenuRef.current) return;
351 if (
352 event.target instanceof Node &&
353 !editorMenuRef.current.contains(event.target)
354 ) {
341 if (event.target instanceof Node && !editorMenuRef.current.contains(event.target)) {
355342 setIsEditorMenuOpen(false);
356343 }
357344 };
......@@ -368,23 +355,25 @@ export default function ChatView() {
368355 if (e.key === "o" && (e.metaKey || e.ctrlKey) && !e.shiftKey) {
369356 if (api && activeProject) {
370357 e.preventDefault();
371 void api.shell.openInEditor(activeProject.cwd, lastEditor);
358 const cwd = activeThread?.worktreePath ?? activeProject.cwd;
359 void api.shell.openInEditor(cwd, lastEditor);
372360 }
373361 }
374362 };
375363 window.addEventListener("keydown", handler);
376364 return () => window.removeEventListener("keydown", handler);
377 }, [api, activeProject, lastEditor]);
365 }, [api, activeProject, activeThread, lastEditor]);
378366
379367 const openInEditor = (editorId: EditorId) => {
380368 if (!api || !activeProject) return;
381 void api.shell.openInEditor(activeProject.cwd, editorId);
369 const cwd = activeThread?.worktreePath ?? activeProject.cwd;
370 void api.shell.openInEditor(cwd, editorId);
382371 setLastEditor(editorId);
383372 localStorage.setItem(LAST_EDITOR_KEY, editorId);
384373 setIsEditorMenuOpen(false);
385374 };
386375
387 const ensureSession = async (): Promise<EnsuredSessionInfo | null> => {
376 const ensureSession = async (cwdOverride?: string): Promise<EnsuredSessionInfo | null> => {
388377 if (!api || !activeThread || !activeProject) return null;
389378 if (activeThread.session && activeThread.session.status !== "closed") {
390379 const sessionThreadId = activeThread.session.threadId ?? null;
......@@ -406,7 +395,7 @@ export default function ChatView() {
406395 try {
407396 const session = await api.providers.startSession({
408397 provider: "codex",
409 cwd: activeProject.cwd || undefined,
398 cwd: cwdOverride ?? activeThread.worktreePath ?? activeProject.cwd,
410399 model: selectedModel || undefined,
411400 resumeThreadId: priorCodexThreadId ?? undefined,
412401 approvalPolicy: runtimeSessionConfig.approvalPolicy,
......@@ -446,6 +435,39 @@ export default function ChatView() {
446435 if (!api || !activeThread || isSending || isConnecting) return;
447436 const trimmed = prompt.trim();
448437 if (!trimmed) return;
438 if (!activeProject) return;
439
440 // On first message: lock in branch + create worktree if needed.
441 let sessionCwd: string | undefined;
442 if (
443 activeThread.messages.length === 0 &&
444 activeThread.branch &&
445 envMode === "worktree" &&
446 !activeThread.worktreePath
447 ) {
448 try {
449 const newBranch = `codething/${crypto.randomUUID().slice(0, 8)}`;
450 const result = await api.git.createWorktree({
451 cwd: activeProject.cwd,
452 branch: activeThread.branch,
453 newBranch,
454 });
455 sessionCwd = result.worktree.path;
456 dispatch({
457 type: "SET_THREAD_BRANCH",
458 threadId: activeThread.id,
459 branch: result.worktree.branch,
460 worktreePath: result.worktree.path,
461 });
462 } catch (err) {
463 dispatch({
464 type: "SET_ERROR",
465 threadId: activeThread.id,
466 error: err instanceof Error ? err.message : "Failed to create worktree",
467 });
468 return;
469 }
470 }
449471
450472 // Auto-title from first message
451473 if (activeThread.messages.length === 0) {
......@@ -471,21 +493,16 @@ export default function ChatView() {
471493 const previousMessages = activeThread.messages;
472494 setPrompt("");
473495
474 const sessionInfo = await ensureSession();
496 const sessionInfo = await ensureSession(sessionCwd);
475497 if (!sessionInfo) return;
476498
477499 setIsSending(true);
478500 try {
479501 const shouldBootstrap =
480502 previousMessages.length > 0 &&
481 (sessionInfo.continuityState === "new" ||
482 sessionInfo.continuityState === "fallback_new");
503 (sessionInfo.continuityState === "new" || sessionInfo.continuityState === "fallback_new");
483504 const input = shouldBootstrap
484 ? buildBootstrapInput(
485 previousMessages,
486 trimmed,
487 PROVIDER_SEND_TURN_MAX_INPUT_CHARS,
488 ).text
505 ? buildBootstrapInput(previousMessages, trimmed, PROVIDER_SEND_TURN_MAX_INPUT_CHARS).text
489506 : trimmed;
490507 await api.providers.sendTurn({
491508 sessionId: sessionInfo.sessionId,
......@@ -512,10 +529,7 @@ export default function ChatView() {
512529 });
513530 };
514531
515 const onRespondToApproval = async (
516 requestId: string,
517 decision: ProviderApprovalDecision,
518 ) => {
532 const onRespondToApproval = async (requestId: string, decision: ProviderApprovalDecision) => {
519533 if (!api || !activeThread?.session) return;
520534
521535 setRespondingRequestIds((existing) =>
......@@ -531,15 +545,10 @@ export default function ChatView() {
531545 dispatch({
532546 type: "SET_ERROR",
533547 threadId: activeThread.id,
534 error:
535 err instanceof Error
536 ? err.message
537 : "Failed to submit approval decision.",
548 error: err instanceof Error ? err.message : "Failed to submit approval decision.",
538549 });
539550 } finally {
540 setRespondingRequestIds((existing) =>
541 existing.filter((id) => id !== requestId),
542 );
551 setRespondingRequestIds((existing) => existing.filter((id) => id !== requestId));
543552 }
544553 };
545554
......@@ -577,11 +586,22 @@ export default function ChatView() {
577586 return (
578587 <div className="flex flex-1 flex-col bg-background">
579588 {/* Top bar */}
580 <header className={`flex items-center justify-between border-b border-border px-5 pb-3 ${isElectron ? "drag-region pt-[28px]" : "pt-3"}`}>
589 <header
590 className={`flex items-center justify-between border-b border-border px-5 pb-3 ${isElectron ? "drag-region pt-[28px]" : "pt-3"}`}
591 >
581592 <div className="flex items-center gap-3">
582 <h2 className="text-sm font-medium text-foreground">
583 {activeThread.title}
584 </h2>
593 <h2 className="text-sm font-medium text-foreground">{activeThread.title}</h2>
594 {activeProject && (
595 <span className="rounded-full bg-accent px-2 py-0.5 text-[10px] text-muted-foreground/50">
596 {activeProject.name}
597 </span>
598 )}
599 {activeThread.branch && (
600 <span className="rounded-full bg-accent px-2 py-0.5 font-mono text-[10px] text-muted-foreground/50">
601 {activeThread.branch}
602 {activeThread.worktreePath ? " (worktree)" : ""}
603 </span>
604 )}
585605 </div>
586606 <div className="flex items-center gap-3">
587607 {/* Open in editor */}
......@@ -606,9 +626,7 @@ export default function ChatView() {
606626 {editorLabel(editor)}
607627 {editor.id === lastEditor && (
608628 <kbd className="ml-auto text-[9px] text-muted-foreground/40">
609 {navigator.platform.includes("Mac")
610 ? "\u2318O"
611 : "Ctrl+O"}
629 {navigator.platform.includes("Mac") ? "\u2318O" : "Ctrl+O"}
612630 </kbd>
613631 )}
614632 </button>
......@@ -634,7 +652,7 @@ export default function ChatView() {
634652
635653 {/* Error banner */}
636654 {activeThread.error && (
637 <div className="mx-4 mt-3 rounded-lg border border-rose-400/20 bg-rose-900/20 px-3 py-2 text-xs text-rose-200">
655 <div className="mx-4 mt-3 rounded-lg border border-destructive/20 bg-destructive/10 px-3 py-2 text-xs text-destructive">
638656 {activeThread.error}
639657 </div>
640658 )}
......@@ -642,9 +660,7 @@ export default function ChatView() {
642660 {pendingApprovals.length > 0 && (
643661 <div className="mx-4 mt-3 space-y-2">
644662 {pendingApprovals.map((approval) => {
645 const isResponding = respondingRequestIds.includes(
646 approval.requestId,
647 );
663 const isResponding = respondingRequestIds.includes(approval.requestId);
648664 return (
649665 <div
650666 key={approval.requestId}
......@@ -668,9 +684,7 @@ export default function ChatView() {
668684 type="button"
669685 className="rounded-md border border-border bg-accent px-2 py-1 text-[11px] text-foreground transition-colors duration-150 hover:bg-accent/80 disabled:cursor-not-allowed disabled:opacity-50"
670686 disabled={isResponding}
671 onClick={() =>
672 void onRespondToApproval(approval.requestId, "accept")
673 }
687 onClick={() => void onRespondToApproval(approval.requestId, "accept")}
674688 >
675689 Approve once
676690 </button>
......@@ -678,12 +692,7 @@ export default function ChatView() {
678692 type="button"
679693 className="rounded-md border border-sky-300/30 bg-sky-500/[0.15] px-2 py-1 text-[11px] text-sky-100 transition-colors duration-150 hover:bg-sky-500/[0.22] disabled:cursor-not-allowed disabled:opacity-50"
680694 disabled={isResponding}
681 onClick={() =>
682 void onRespondToApproval(
683 approval.requestId,
684 "acceptForSession",
685 )
686 }
695 onClick={() => void onRespondToApproval(approval.requestId, "acceptForSession")}
687696 >
688697 Always allow this session
689698 </button>
......@@ -691,9 +700,7 @@ export default function ChatView() {
691700 type="button"
692701 className="rounded-md border border-border px-2 py-1 text-[11px] text-foreground/90 transition-colors duration-150 hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50"
693702 disabled={isResponding}
694 onClick={() =>
695 void onRespondToApproval(approval.requestId, "decline")
696 }
703 onClick={() => void onRespondToApproval(approval.requestId, "decline")}
697704 >
698705 Decline
699706 </button>
......@@ -701,9 +708,7 @@ export default function ChatView() {
701708 type="button"
702709 className="rounded-md border border-rose-300/30 bg-rose-500/[0.12] px-2 py-1 text-[11px] text-rose-100 transition-colors duration-150 hover:bg-rose-500/[0.2] disabled:cursor-not-allowed disabled:opacity-50"
703710 disabled={isResponding}
704 onClick={() =>
705 void onRespondToApproval(approval.requestId, "cancel")
706 }
711 onClick={() => void onRespondToApproval(approval.requestId, "cancel")}
707712 >
708713 Cancel turn
709714 </button>
......@@ -718,15 +723,14 @@ export default function ChatView() {
718723 <div className="flex-1 overflow-y-auto px-5 py-4">
719724 {activeThread.messages.length === 0 && !isWorking ? (
720725 <div className="flex h-full items-center justify-center">
721 <p className="text-sm text-muted-foreground/30">Send a message to start the conversation.</p>
726 <p className="text-sm text-muted-foreground/30">
727 Send a message to start the conversation.
728 </p>
722729 </div>
723730 ) : (
724731 <div className="mx-auto max-w-3xl space-y-4">
725732 {timelineEntries.map((timelineEntry, index) => {
726 if (
727 timelineEntry.kind === "work" &&
728 timelineEntries[index - 1]?.kind === "work"
729 ) {
733 if (timelineEntry.kind === "work" && timelineEntries[index - 1]?.kind === "work") {
730734 return null;
731735 }
732736
......@@ -747,16 +751,13 @@ export default function ChatView() {
747751
748752 const groupId = timelineEntry.id;
749753 const isExpanded = expandedWorkGroups[groupId] ?? false;
750 const hasOverflow =
751 groupedEntries.length > MAX_VISIBLE_WORK_LOG_ENTRIES;
754 const hasOverflow = groupedEntries.length > MAX_VISIBLE_WORK_LOG_ENTRIES;
752755 const visibleEntries =
753756 hasOverflow && !isExpanded
754757 ? groupedEntries.slice(-MAX_VISIBLE_WORK_LOG_ENTRIES)
755758 : groupedEntries;
756759 const hiddenCount = groupedEntries.length - visibleEntries.length;
757 const onlyToolEntries = groupedEntries.every(
758 (entry) => entry.tone === "tool",
759 );
760 const onlyToolEntries = groupedEntries.every((entry) => entry.tone === "tool");
760761 const groupLabel = onlyToolEntries
761762 ? groupedEntries.length === 1
762763 ? "Tool call"
......@@ -842,9 +843,7 @@ export default function ChatView() {
842843 <div className="my-3 flex items-center gap-3">
843844 <span className="h-px flex-1 bg-border" />
844845 <span className="rounded-full border border-border bg-background px-2.5 py-1 text-[10px] uppercase tracking-[0.14em] text-muted-foreground/80">
845 {completionSummary
846 ? `Response • ${completionSummary}`
847 : "Response"}
846 {completionSummary ? `Response • ${completionSummary}` : "Response"}
848847 </span>
849848 <span className="h-px flex-1 bg-border" />
850849 </div>
......@@ -853,24 +852,17 @@ export default function ChatView() {
853852 <ChatMarkdown
854853 text={
855854 timelineEntry.message.text ||
856 (timelineEntry.message.streaming
857 ? ""
858 : "(empty response)")
855 (timelineEntry.message.streaming ? "" : "(empty response)")
859856 }
860857 />
861858 <p className="mt-1.5 text-[10px] text-muted-foreground/30">
862859 {formatMessageMeta(
863860 timelineEntry.message.createdAt,
864861 timelineEntry.message.streaming
865 ? formatElapsed(
866 timelineEntry.message.createdAt,
867 nowIso,
868 )
862 ? formatElapsed(timelineEntry.message.createdAt, nowIso)
869863 : formatElapsed(
870864 timelineEntry.message.createdAt,
871 assistantCompletionByItemId.get(
872 timelineEntry.message.id,
873 ),
865 assistantCompletionByItemId.get(timelineEntry.message.id),
874866 ),
875867 )}
876868 </p>
......@@ -896,7 +888,7 @@ export default function ChatView() {
896888 </div>
897889
898890 {/* Input bar */}
899 <div className="px-5 pb-4 pt-2">
891 <div className="px-5 pb-1 pt-2">
900892 <form onSubmit={onSend} className="mx-auto max-w-3xl">
901893 <div className="group rounded-[20px] border border-border bg-card transition-colors duration-200 focus-within:border-ring">
902894 {/* Textarea area */}
......@@ -1026,9 +1018,7 @@ export default function ChatView() {
10261018 disabled={isSwitchingRuntimeMode}
10271019 onClick={() =>
10281020 void handleRuntimeModeChange(
1029 state.runtimeMode === "full-access"
1030 ? "approval-required"
1031 : "full-access",
1021 state.runtimeMode === "full-access" ? "approval-required" : "full-access",
10321022 )
10331023 }
10341024 title={
......@@ -1038,13 +1028,7 @@ export default function ChatView() {
10381028 }
10391029 >
10401030 {state.runtimeMode === "full-access" ? (
1041 <svg
1042 width="14"
1043 height="14"
1044 viewBox="0 0 14 14"
1045 fill="none"
1046 aria-hidden="true"
1047 >
1031 <svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden="true">
10481032 <rect
10491033 x="2"
10501034 y="5.5"
......@@ -1062,13 +1046,7 @@ export default function ChatView() {
10621046 />
10631047 </svg>
10641048 ) : (
1065 <svg
1066 width="14"
1067 height="14"
1068 viewBox="0 0 14 14"
1069 fill="none"
1070 aria-hidden="true"
1071 >
1049 <svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden="true">
10721050 <rect
10731051 x="2"
10741052 y="5.5"
......@@ -1086,11 +1064,7 @@ export default function ChatView() {
10861064 />
10871065 </svg>
10881066 )}
1089 <span>
1090 {state.runtimeMode === "full-access"
1091 ? "Full access"
1092 : "Supervised"}
1093 </span>
1067 <span>{state.runtimeMode === "full-access" ? "Full access" : "Supervised"}</span>
10941068 </button>
10951069 </div>
10961070
......@@ -1165,6 +1139,8 @@ export default function ChatView() {
11651139 </div>
11661140 </form>
11671141 </div>
1142
1143 <BranchToolbar envMode={envMode} onEnvModeChange={setEnvMode} envLocked={envLocked} />
11681144 </div>
11691145 );
11701146}
apps/web/src/components/DiffPanel.tsx+3-1
......@@ -7,7 +7,9 @@ export default function DiffPanel() {
77 return (
88 <aside className="flex h-full w-[400px] shrink-0 flex-col border-l border-border bg-card">
99 {/* Header */}
10 <div className={`flex items-center justify-between border-b border-border px-4 pb-3 ${isElectron ? "drag-region pt-[28px]" : "pt-3"}`}>
10 <div
11 className={`flex items-center justify-between border-b border-border px-4 pb-3 ${isElectron ? "drag-region pt-[28px]" : "pt-3"}`}
12 >
1113 <h3 className="text-xs font-medium text-foreground">Uncommitted changes</h3>
1214 <button
1315 type="button"
apps/web/src/components/Sidebar.tsx+2
......@@ -57,6 +57,8 @@ export default function Sidebar() {
5757 events: [],
5858 error: null,
5959 createdAt: new Date().toISOString(),
60 branch: null,
61 worktreePath: null,
6062 },
6163 });
6264 },
apps/web/src/historyBootstrap.ts+4-11
......@@ -36,13 +36,8 @@ export function buildBootstrapInput(
3636 latestPrompt: string,
3737 maxChars: number,
3838): BootstrapInputResult {
39 const budget = Number.isFinite(maxChars)
40 ? Math.max(1, Math.floor(maxChars))
41 : 1;
42 const promptOnly =
43 latestPrompt.length <= budget
44 ? latestPrompt
45 : latestPrompt.slice(0, budget);
39 const budget = Number.isFinite(maxChars) ? Math.max(1, Math.floor(maxChars)) : 1;
40 const promptOnly = latestPrompt.length <= budget ? latestPrompt : latestPrompt.slice(0, budget);
4641
4742 if (previousMessages.length === 0) {
4843 return {
......@@ -87,8 +82,7 @@ export function buildBootstrapInput(
8782
8883 let includedChronological = [...includedNewestFirst].reverse();
8984 while (true) {
90 const omittedCount =
91 newestFirstBlocks.length - includedChronological.length;
85 const omittedCount = newestFirstBlocks.length - includedChronological.length;
9286 const transcriptBody =
9387 omittedCount > 0
9488 ? includedChronological.length > 0
......@@ -101,8 +95,7 @@ export function buildBootstrapInput(
10195 text: finalized,
10296 includedCount: includedChronological.length,
10397 omittedCount,
104 truncated:
105 omittedCount > 0 || latestPrompt.length !== promptOnly.length,
98 truncated: omittedCount > 0 || latestPrompt.length !== promptOnly.length,
10699 };
107100 }
108101
apps/web/src/index.css+11-26
......@@ -88,11 +88,7 @@
8888 --secondary: --alpha(var(--color-black) / 4%);
8989 --secondary-foreground: var(--color-neutral-800);
9090 --muted: --alpha(var(--color-black) / 4%);
91 --muted-foreground: color-mix(
92 in srgb,
93 var(--color-neutral-500) 90%,
94 var(--color-black)
95 );
91 --muted-foreground: color-mix(in srgb, var(--color-neutral-500) 90%, var(--color-black));
9692 --accent: --alpha(var(--color-black) / 5%);
9793 --accent-foreground: var(--color-neutral-800);
9894 --destructive: var(--color-red-500);
......@@ -122,11 +118,7 @@
122118
123119 @variant dark {
124120 color-scheme: dark;
125 --background: color-mix(
126 in srgb,
127 var(--color-neutral-950) 95%,
128 var(--color-white)
129 );
121 --background: color-mix(in srgb, var(--color-neutral-950) 95%, var(--color-white));
130122 --foreground: var(--color-neutral-100);
131123 --card: color-mix(in srgb, var(--background) 98%, var(--color-white));
132124 --card-foreground: var(--color-neutral-100);
......@@ -137,18 +129,10 @@
137129 --secondary: --alpha(var(--color-white) / 4%);
138130 --secondary-foreground: var(--color-neutral-100);
139131 --muted: --alpha(var(--color-white) / 4%);
140 --muted-foreground: color-mix(
141 in srgb,
142 var(--color-neutral-500) 90%,
143 var(--color-white)
144 );
132 --muted-foreground: color-mix(in srgb, var(--color-neutral-500) 90%, var(--color-white));
145133 --accent: --alpha(var(--color-white) / 4%);
146134 --accent-foreground: var(--color-neutral-100);
147 --destructive: color-mix(
148 in srgb,
149 var(--color-red-500) 90%,
150 var(--color-white)
151 );
135 --destructive: color-mix(in srgb, var(--color-red-500) 90%, var(--color-white));
152136 --border: --alpha(var(--color-white) / 6%);
153137 --input: --alpha(var(--color-white) / 8%);
154138 --ring: oklch(0.588 0.217 264);
......@@ -177,7 +161,12 @@
177161
178162body {
179163 font-family:
180 "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
164 "DM Sans",
165 -apple-system,
166 BlinkMacSystemFont,
167 "Segoe UI",
168 system-ui,
169 sans-serif;
181170 margin: 0;
182171 padding: 0;
183172 min-height: 100vh;
......@@ -287,11 +276,7 @@ label:has(> select#reasoning-effort) select {
287276.chat-markdown a {
288277 color: var(--info-foreground);
289278 text-decoration: underline;
290 text-decoration-color: color-mix(
291 in srgb,
292 var(--info-foreground) 40%,
293 transparent
294 );
279 text-decoration-color: color-mix(in srgb, var(--info-foreground) 40%, transparent);
295280}
296281
297282.chat-markdown a:hover {
apps/web/src/persistenceSchema.test.ts+4
......@@ -134,6 +134,8 @@ describe("toPersistedState", () => {
134134 events: [],
135135 error: "boom",
136136 createdAt: "2026-02-08T10:00:00.000Z",
137 branch: null,
138 worktreePath: null,
137139 };
138140
139141 const persisted = toPersistedState({
......@@ -161,6 +163,8 @@ describe("toPersistedState", () => {
161163 model: "gpt-5.3-codex",
162164 messages: thread.messages,
163165 createdAt: thread.createdAt,
166 branch: null,
167 worktreePath: null,
164168 });
165169 const persistedThread = persisted.threads[0];
166170 expect(persistedThread).toBeDefined();
apps/web/src/persistenceSchema.ts+9-12
......@@ -1,12 +1,7 @@
11import { z } from "zod";
22
33import { DEFAULT_MODEL, resolveModelSlug } from "./model-logic";
4import {
5 DEFAULT_RUNTIME_MODE,
6 type Project,
7 type RuntimeMode,
8 type Thread,
9} from "./types";
4import { DEFAULT_RUNTIME_MODE, type Project, type RuntimeMode, type Thread } from "./types";
105
116const LEGACY_DEFAULT_MODEL = "gpt-5.2-codex";
127
......@@ -34,6 +29,8 @@ const persistedThreadSchema = z.object({
3429 model: z.string().min(1),
3530 messages: z.array(persistedMessageSchema),
3631 createdAt: z.string().min(1),
32 branch: z.string().min(1).nullable().optional(),
33 worktreePath: z.string().min(1).nullable().optional(),
3734});
3835
3936const persistedStateBodySchema = z.object({
......@@ -112,6 +109,8 @@ function hydrateThread(
112109 events: [],
113110 error: null,
114111 createdAt: thread.createdAt,
112 branch: thread.branch ?? null,
113 worktreePath: thread.worktreePath ?? null,
115114 };
116115}
117116
......@@ -146,13 +145,9 @@ export function hydratePersistedState(
146145 return {
147146 projects,
148147 threads,
149 activeThreadId: hasActiveThread
150 ? parsedState.data.activeThreadId
151 : (threads[0]?.id ?? null),
148 activeThreadId: hasActiveThread ? parsedState.data.activeThreadId : (threads[0]?.id ?? null),
152149 runtimeMode:
153 "runtimeMode" in parsedState.data
154 ? parsedState.data.runtimeMode
155 : DEFAULT_RUNTIME_MODE,
150 "runtimeMode" in parsedState.data ? parsedState.data.runtimeMode : DEFAULT_RUNTIME_MODE,
156151 };
157152}
158153
......@@ -170,6 +165,8 @@ export function toPersistedState(
170165 model: thread.model,
171166 messages: thread.messages,
172167 createdAt: thread.createdAt,
168 branch: thread.branch,
169 worktreePath: thread.worktreePath,
173170 })),
174171 activeThreadId: state.activeThreadId,
175172 runtimeMode: state.runtimeMode,
apps/web/src/session-logic.ts+5-20
......@@ -109,11 +109,7 @@ function normalizeItemType(raw: string | undefined): string {
109109}
110110
111111function shouldDropItemType(type: string): boolean {
112 if (
113 type.includes("preamble") ||
114 type.includes("reasoning") ||
115 type.includes("thought")
116 ) {
112 if (type.includes("preamble") || type.includes("reasoning") || type.includes("thought")) {
117113 return true;
118114 }
119115
......@@ -121,11 +117,7 @@ function shouldDropItemType(type: string): boolean {
121117}
122118
123119function shouldShowItemLifecycle(type: string): boolean {
124 return (
125 type.includes("tool") ||
126 type.includes("command") ||
127 type.includes("file change")
128 );
120 return type.includes("tool") || type.includes("command") || type.includes("file change");
129121}
130122
131123function shouldDropMethod(method: string): boolean {
......@@ -182,9 +174,7 @@ function extractDetail(
182174 return undefined;
183175}
184176
185function lifecycleCandidateFromItemEvent(
186 event: ProviderEvent,
187): ItemLifecycleCandidate | null {
177function lifecycleCandidateFromItemEvent(event: ProviderEvent): ItemLifecycleCandidate | null {
188178 const payload = asObject(event.payload);
189179 const item = asObject(payload?.item);
190180 const normalizedType = normalizeItemType(asString(item?.type));
......@@ -360,10 +350,7 @@ export function deriveWorkLogEntries(
360350 ) {
361351 continue;
362352 }
363 if (
364 lifecycleCandidate.label === "Tool call" &&
365 !lifecycleCandidate.detail
366 ) {
353 if (lifecycleCandidate.label === "Tool call" && !lifecycleCandidate.detail) {
367354 continue;
368355 }
369356
......@@ -371,9 +358,7 @@ export function deriveWorkLogEntries(
371358 id: lifecycleCandidate.id,
372359 createdAt: lifecycleCandidate.createdAt,
373360 label: lifecycleCandidate.label,
374 ...(lifecycleCandidate.detail
375 ? { detail: lifecycleCandidate.detail }
376 : {}),
361 ...(lifecycleCandidate.detail ? { detail: lifecycleCandidate.detail } : {}),
377362 tone: lifecycleCandidate.tone,
378363 });
379364 continue;
apps/web/src/store.test.ts+2
......@@ -39,6 +39,8 @@ function makeThread(overrides: Partial<Thread> = {}): Thread {
3939 events: [],
4040 error: null,
4141 createdAt: "2026-02-09T00:00:00.000Z",
42 branch: null,
43 worktreePath: null,
4244 ...overrides,
4345 };
4446}
apps/web/src/store.ts+25-3
......@@ -33,6 +33,12 @@ type Action =
3333 | { type: "SET_ERROR"; threadId: string; error: string | null }
3434 | { type: "SET_THREAD_TITLE"; threadId: string; title: string }
3535 | { type: "SET_THREAD_MODEL"; threadId: string; model: string }
36 | {
37 type: "SET_THREAD_BRANCH";
38 threadId: string;
39 branch: string | null;
40 worktreePath: string | null;
41 }
3642 | { type: "SET_RUNTIME_MODE"; mode: RuntimeMode }
3743 | { type: "DELETE_THREAD"; threadId: string };
3844
......@@ -370,6 +376,24 @@ export function reducer(state: AppState, action: Action): AppState {
370376 })),
371377 };
372378
379 case "SET_THREAD_BRANCH": {
380 return {
381 ...state,
382 threads: updateThread(state.threads, action.threadId, (t) => {
383 // When the effective cwd changes (worktreePath differs), the old
384 // session is no longer valid — clear it so ensureSession creates a
385 // new one with the correct cwd on the next message.
386 const cwdChanged = t.worktreePath !== action.worktreePath;
387 return {
388 ...t,
389 branch: action.branch,
390 worktreePath: action.worktreePath,
391 ...(cwdChanged ? { session: null } : {}),
392 };
393 }),
394 };
395 }
396
373397 case "SET_RUNTIME_MODE":
374398 return {
375399 ...state,
......@@ -379,9 +403,7 @@ export function reducer(state: AppState, action: Action): AppState {
379403 case "DELETE_THREAD": {
380404 const threads = state.threads.filter((t) => t.id !== action.threadId);
381405 const activeThreadId =
382 state.activeThreadId === action.threadId
383 ? (threads[0]?.id ?? null)
384 : state.activeThreadId;
406 state.activeThreadId === action.threadId ? (threads[0]?.id ?? null) : state.activeThreadId;
385407 return { ...state, threads, activeThreadId };
386408 }
387409
apps/web/src/types.ts+2
......@@ -35,4 +35,6 @@ export interface Thread {
3535 latestTurnStartedAt?: string | undefined;
3636 latestTurnCompletedAt?: string | undefined;
3737 latestTurnDurationMs?: number | undefined;
38 branch: string | null;
39 worktreePath: string | null;
3840}
apps/web/src/wsNativeApi.ts+8
......@@ -96,6 +96,14 @@ export function createWsNativeApi(): NativeApi {
9696 openInEditor: (cwd, editor) =>
9797 transport.request(WS_METHODS.shellOpenInEditor, { cwd, editor }),
9898 },
99 git: {
100 listBranches: (input) => transport.request(WS_METHODS.gitListBranches, input),
101 createWorktree: (input) => transport.request(WS_METHODS.gitCreateWorktree, input),
102 removeWorktree: (input) => transport.request(WS_METHODS.gitRemoveWorktree, input),
103 createBranch: (input) => transport.request(WS_METHODS.gitCreateBranch, input),
104 checkout: (input) => transport.request(WS_METHODS.gitCheckout, input),
105 init: (input) => transport.request(WS_METHODS.gitInit, input),
106 },
99107 contextMenu: {
100108 show: async <T extends string>(
101109 items: readonly { id: T; label: string }[],
apps/web/turbo.jsonc created+9
......@@ -0,0 +1,9 @@
1{
2 "$schema": "https://turbo.build/schema.json",
3 "extends": ["//"],
4 "tasks": {
5 "dev": {
6 "persistent": true,
7 },
8 },
9}
apps/web/vite.config.ts+11-4
......@@ -2,6 +2,8 @@ import tailwindcss from "@tailwindcss/vite";
22import react from "@vitejs/plugin-react";
33import { defineConfig } from "vite";
44
5const port = Number(process.env.PORT ?? 5173);
6
57export default defineConfig({
68 plugins: [
79 react({
......@@ -13,13 +15,18 @@ export default defineConfig({
1315 ],
1416 define: {
1517 // In dev mode, tell the web app where the WebSocket server lives
16 "import.meta.env.VITE_WS_URL": JSON.stringify(
17 process.env.VITE_WS_URL ?? "",
18 ),
18 "import.meta.env.VITE_WS_URL": JSON.stringify(process.env.VITE_WS_URL ?? ""),
1919 },
2020 server: {
21 port: Number(process.env.PORT ?? 5173),
21 port,
2222 strictPort: true,
23 hmr: {
24 // Explicit config so Vite's HMR WebSocket connects reliably
25 // inside Electron's BrowserWindow. Vite 8 uses console.debug for
26 // connection logs — enable "Verbose" in DevTools to see them.
27 protocol: "ws",
28 host: "localhost",
29 },
2330 },
2431 build: {
2532 outDir: "dist",
bun.lock+315-168
......@@ -9,7 +9,7 @@
99 "oxlint": "^1.43.0",
1010 "turbo": "^2.3.3",
1111 "typescript": "^5.7.3",
12 "vitest": "^3.0.0",
12 "vitest": "^4.0.0",
1313 },
1414 },
1515 "apps/desktop": {
......@@ -20,11 +20,10 @@
2020 },
2121 "devDependencies": {
2222 "@types/node": "^22.10.2",
23 "concurrently": "^9.1.2",
2423 "electronmon": "^2.0.2",
25 "tsup": "^8.3.5",
24 "tsdown": "^0.20.3",
2625 "typescript": "^5.7.3",
27 "vitest": "^3.0.0",
26 "vitest": "^4.0.0",
2827 "wait-on": "^8.0.2",
2928 },
3029 },
......@@ -43,8 +42,7 @@
4342 "@t3tools/web": "workspace:*",
4443 "@types/node": "^22.10.2",
4544 "@types/ws": "^8.5.13",
46 "tsup": "^8.3.5",
47 "tsx": "^4.19.0",
45 "tsdown": "^0.20.3",
4846 "typescript": "^5.7.3",
4947 },
5048 },
......@@ -53,6 +51,7 @@
5351 "version": "0.0.0",
5452 "dependencies": {
5553 "@t3tools/contracts": "workspace:*",
54 "@tanstack/react-query": "^5.90.0",
5655 "highlight.js": "^11.11.1",
5756 "lucide-react": "^0.563.0",
5857 "react": "^19.0.0",
......@@ -66,11 +65,11 @@
6665 "@tailwindcss/vite": "^4.0.0",
6766 "@types/react": "^19.0.0",
6867 "@types/react-dom": "^19.0.0",
69 "@vitejs/plugin-react": "^4.3.4",
68 "@vitejs/plugin-react": "^5.1.4",
7069 "babel-plugin-react-compiler": "^19.0.0-beta-e552027-20250112",
7170 "tailwindcss": "^4.0.0",
7271 "typescript": "^5.7.3",
73 "vite": "^6.0.5",
72 "vite": "^8.0.0-beta.12",
7473 },
7574 },
7675 "packages/contracts": {
......@@ -80,7 +79,7 @@
8079 "zod": "^3.24.1",
8180 },
8281 "devDependencies": {
83 "tsup": "^8.3.5",
82 "tsdown": "^0.20.3",
8483 "typescript": "^5.7.3",
8584 },
8685 },
......@@ -92,7 +91,7 @@
9291
9392 "@babel/core": ["@babel/core@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA=="],
9493
95 "@babel/generator": ["@babel/generator@7.29.1", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw=="],
94 "@babel/generator": ["@babel/generator@8.0.0-rc.1", "", { "dependencies": { "@babel/parser": "^8.0.0-rc.1", "@babel/types": "^8.0.0-rc.1", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "@types/jsesc": "^2.5.0", "jsesc": "^3.0.2" } }, "sha512-3ypWOOiC4AYHKr8vYRVtWtWmyvcoItHtVqF8paFax+ydpmUdPsJpLBkBBs5ItmhdrwC3a0ZSqqFAdzls4ODP3w=="],
9695
9796 "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.28.6", "", { "dependencies": { "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA=="],
9897
......@@ -106,13 +105,13 @@
106105
107106 "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
108107
109 "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
108 "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@8.0.0-rc.1", "", {}, "sha512-I4YnARytXC2RzkLNVnf5qFNFMzp679qZpmtw/V3Jt2uGnWiIxyJtaukjG7R8pSx8nG2NamICpGfljQsogj+FbQ=="],
110109
111110 "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="],
112111
113112 "@babel/helpers": ["@babel/helpers@7.28.6", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw=="],
114113
115 "@babel/parser": ["@babel/parser@7.29.0", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww=="],
114 "@babel/parser": ["@babel/parser@8.0.0-rc.1", "", { "dependencies": { "@babel/types": "^8.0.0-rc.1" }, "bin": "./bin/babel-parser.js" }, "sha512-6HyyU5l1yK/7h9Ki52i5h6mDAx4qJdiLQO4FdCyJNoB/gy3T3GGJdhQzzbZgvgZCugYBvwtQiWRt94QKedHnkA=="],
116115
117116 "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="],
118117
......@@ -126,6 +125,12 @@
126125
127126 "@electron/get": ["@electron/get@2.0.3", "", { "dependencies": { "debug": "^4.1.1", "env-paths": "^2.2.0", "fs-extra": "^8.1.0", "got": "^11.8.5", "progress": "^2.0.3", "semver": "^6.2.0", "sumchecker": "^3.0.1" }, "optionalDependencies": { "global-agent": "^3.0.0" } }, "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ=="],
128127
128 "@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="],
129
130 "@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="],
131
132 "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
133
129134 "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg=="],
130135
131136 "@esbuild/android-arm": ["@esbuild/android-arm@0.27.3", "", { "os": "android", "cpu": "arm" }, "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA=="],
......@@ -200,6 +205,12 @@
200205
201206 "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
202207
208 "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" } }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="],
209
210 "@oxc-project/runtime": ["@oxc-project/runtime@0.112.0", "", {}, "sha512-4vYtWXMnXM6EaweCxbJ6bISAhkNHeN33SihvuX3wrpqaSJA4ZEoW35i9mSvE74+GDf1yTeVE+aEHA+WBpjDk/g=="],
211
212 "@oxc-project/types": ["@oxc-project/types@0.112.0", "", {}, "sha512-m6RebKHIRsax2iCwVpYW2ErQwa4ywHJrE4sCK3/8JK8ZZAWOKXaRJFl/uP51gaVyyXlaS4+chU1nSCdzYf6QqQ=="],
213
203214 "@oxfmt/darwin-arm64": ["@oxfmt/darwin-arm64@0.28.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-jmUfF7cNJPw57bEK7sMIqrYRgn4LH428tSgtgLTCtjuGuu1ShREyrkeB7y8HtkXRfhBs4lVY+HMLhqElJvZ6ww=="],
204215
205216 "@oxfmt/darwin-x64": ["@oxfmt/darwin-x64@0.28.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-S6vlV8S7jbjzJOSjfVg2CimUC0r7/aHDLdUm/3+/B/SU/s1jV7ivqWkMv1/8EB43d1BBwT9JQ60ZMTkBqeXSFA=="],
......@@ -232,7 +243,35 @@
232243
233244 "@oxlint/win32-x64": ["@oxlint/win32-x64@1.43.0", "", { "os": "win32", "cpu": "x64" }, "sha512-bSuItSU8mTSDsvmmLTepTdCL2FkJI6dwt9tot/k0EmiYF+ArRzmsl4lXVLssJNRV5lJEc5IViyTrh7oiwrjUqA=="],
234245
235 "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.27", "", {}, "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA=="],
246 "@quansync/fs": ["@quansync/fs@1.0.0", "", { "dependencies": { "quansync": "^1.0.0" } }, "sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ=="],
247
248 "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-rc.3", "", { "os": "android", "cpu": "arm64" }, "sha512-0T1k9FinuBZ/t7rZ8jN6OpUKPnUjNdYHoj/cESWrQ3ZraAJ4OMm6z7QjSfCxqj8mOp9kTKc1zHK3kGz5vMu+nQ=="],
249
250 "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0-rc.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-JWWLzvcmc/3pe7qdJqPpuPk91SoE/N+f3PcWx/6ZwuyDVyungAEJPvKm/eEldiDdwTmaEzWfIR+HORxYWrCi1A=="],
251
252 "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.0-rc.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-MTakBxfx3tde5WSmbHxuqlDsIW0EzQym+PJYGF4P6lG2NmKzi128OGynoFUqoD5ryCySEY85dug4v+LWGBElIw=="],
253
254 "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.0-rc.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-jje3oopyOLs7IwfvXoS6Lxnmie5JJO7vW29fdGFu5YGY1EDbVDhD+P9vDihqS5X6fFiqL3ZQZCMBg6jyHkSVww=="],
255
256 "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.3", "", { "os": "linux", "cpu": "arm" }, "sha512-A0n8P3hdLAaqzSFrQoA42p23ZKBYQOw+8EH5r15Sa9X1kD9/JXe0YT2gph2QTWvdr0CVK2BOXiK6ENfy6DXOag=="],
257
258 "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.0-rc.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-kWXkoxxarYISBJ4bLNf5vFkEbb4JvccOwxWDxuK9yee8lg5XA7OpvlTptfRuwEvYcOZf+7VS69Uenpmpyo5Bjw=="],
259
260 "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.0-rc.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-Z03/wrqau9Bicfgb3Dbs6SYTHliELk2PM2LpG2nFd+cGupTMF5kanLEcj2vuuJLLhptNyS61rtk7SOZ+lPsTUA=="],
261
262 "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.0-rc.3", "", { "os": "linux", "cpu": "x64" }, "sha512-iSXXZsQp08CSilff/DCTFZHSVEpEwdicV3W8idHyrByrcsRDVh9sGC3sev6d8BygSGj3vt8GvUKBPCoyMA4tgQ=="],
263
264 "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.0-rc.3", "", { "os": "linux", "cpu": "x64" }, "sha512-qaj+MFudtdCv9xZo9znFvkgoajLdc+vwf0Kz5N44g+LU5XMe+IsACgn3UG7uTRlCCvhMAGXm1XlpEA5bZBrOcw=="],
265
266 "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.0-rc.3", "", { "os": "none", "cpu": "arm64" }, "sha512-U662UnMETyjT65gFmG9ma+XziENrs7BBnENi/27swZPYagubfHRirXHG2oMl+pEax2WvO7Kb9gHZmMakpYqBHQ=="],
267
268 "@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.0-rc.3", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.1.1" }, "cpu": "none" }, "sha512-gekrQ3Q2HiC1T5njGyuUJoGpK/l6B/TNXKed3fZXNf9YRTJn3L5MOZsFBn4bN2+UX+8+7hgdlTcEsexX988G4g=="],
269
270 "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.0-rc.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-85y5JifyMgs8m5K2XzR/VDsapKbiFiohl7s5lEj7nmNGO0pkTXE7q6TQScei96BNAsoK7JC3pA7ukA8WRHVJpg=="],
271
272 "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.0-rc.3", "", { "os": "win32", "cpu": "x64" }, "sha512-a4VUQZH7LxGbUJ3qJ/TzQG8HxdHvf+jOnqf7B7oFx1TEBm+j2KNL2zr5SQ7wHkNAcaPevF6gf9tQnVBnC4mD+A=="],
273
274 "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.3", "", {}, "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q=="],
236275
237276 "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.57.1", "", { "os": "android", "cpu": "arm" }, "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg=="],
238277
......@@ -326,6 +365,12 @@
326365
327366 "@tailwindcss/vite": ["@tailwindcss/vite@4.1.18", "", { "dependencies": { "@tailwindcss/node": "4.1.18", "@tailwindcss/oxide": "4.1.18", "tailwindcss": "4.1.18" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA=="],
328367
368 "@tanstack/query-core": ["@tanstack/query-core@5.90.20", "", {}, "sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg=="],
369
370 "@tanstack/react-query": ["@tanstack/react-query@5.90.21", "", { "dependencies": { "@tanstack/query-core": "5.90.20" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-0Lu6y5t+tvlTJMTO7oh5NSpJfpg/5D41LlThfepTixPYkJ0sE2Jj0m0f6yYqujBwIXlId87e234+MxG3D3g7kg=="],
371
372 "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
373
329374 "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="],
330375
331376 "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="],
......@@ -350,6 +395,8 @@
350395
351396 "@types/http-cache-semantics": ["@types/http-cache-semantics@4.2.0", "", {}, "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q=="],
352397
398 "@types/jsesc": ["@types/jsesc@2.5.1", "", {}, "sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw=="],
399
353400 "@types/keyv": ["@types/keyv@3.1.4", "", { "dependencies": { "@types/node": "*" } }, "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg=="],
354401
355402 "@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="],
......@@ -372,32 +419,30 @@
372419
373420 "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="],
374421
375 "@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="],
376
377 "@vitest/expect": ["@vitest/expect@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" } }, "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig=="],
378
379 "@vitest/mocker": ["@vitest/mocker@3.2.4", "", { "dependencies": { "@vitest/spy": "3.2.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "optionalPeers": ["msw", "vite"] }, "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ=="],
422 "@vitejs/plugin-react": ["@vitejs/plugin-react@5.1.4", "", { "dependencies": { "@babel/core": "^7.29.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-rc.3", "@types/babel__core": "^7.20.5", "react-refresh": "^0.18.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-VIcFLdRi/VYRU8OL/puL7QXMYafHmqOnwTZY50U1JPlCNj30PxCMx65c494b1K9be9hX83KVt0+gTEwTWLqToA=="],
380423
381 "@vitest/pretty-format": ["@vitest/pretty-format@3.2.4", "", { "dependencies": { "tinyrainbow": "^2.0.0" } }, "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA=="],
424 "@vitest/expect": ["@vitest/expect@4.0.18", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.0.18", "@vitest/utils": "4.0.18", "chai": "^6.2.1", "tinyrainbow": "^3.0.3" } }, "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ=="],
382425
383 "@vitest/runner": ["@vitest/runner@3.2.4", "", { "dependencies": { "@vitest/utils": "3.2.4", "pathe": "^2.0.3", "strip-literal": "^3.0.0" } }, "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ=="],
426 "@vitest/mocker": ["@vitest/mocker@4.0.18", "", { "dependencies": { "@vitest/spy": "4.0.18", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0-0" }, "optionalPeers": ["msw", "vite"] }, "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ=="],
384427
385 "@vitest/snapshot": ["@vitest/snapshot@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "magic-string": "^0.30.17", "pathe": "^2.0.3" } }, "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ=="],
428 "@vitest/pretty-format": ["@vitest/pretty-format@4.0.18", "", { "dependencies": { "tinyrainbow": "^3.0.3" } }, "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw=="],
386429
387 "@vitest/spy": ["@vitest/spy@3.2.4", "", { "dependencies": { "tinyspy": "^4.0.3" } }, "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw=="],
430 "@vitest/runner": ["@vitest/runner@4.0.18", "", { "dependencies": { "@vitest/utils": "4.0.18", "pathe": "^2.0.3" } }, "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw=="],
388431
389 "@vitest/utils": ["@vitest/utils@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" } }, "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA=="],
432 "@vitest/snapshot": ["@vitest/snapshot@4.0.18", "", { "dependencies": { "@vitest/pretty-format": "4.0.18", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA=="],
390433
391 "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
434 "@vitest/spy": ["@vitest/spy@4.0.18", "", {}, "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw=="],
392435
393 "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
436 "@vitest/utils": ["@vitest/utils@4.0.18", "", { "dependencies": { "@vitest/pretty-format": "4.0.18", "tinyrainbow": "^3.0.3" } }, "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA=="],
394437
395438 "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
396439
397 "any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="],
440 "ansis": ["ansis@4.2.0", "", {}, "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig=="],
398441
399442 "assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="],
400443
444 "ast-kit": ["ast-kit@3.0.0-beta.1", "", { "dependencies": { "@babel/parser": "^8.0.0-beta.4", "estree-walker": "^3.0.3", "pathe": "^2.0.3" } }, "sha512-trmleAnZ2PxN/loHWVhhx1qeOHSRXq4TDsBBxq3GqeJitfk3+jTQ+v/C1km/KYq9M7wKqCewMh+/NAvVH7m+bw=="],
445
401446 "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="],
402447
403448 "axios": ["axios@1.13.5", "", { "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", "proxy-from-env": "^1.1.0" } }, "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q=="],
......@@ -408,6 +453,8 @@
408453
409454 "baseline-browser-mapping": ["baseline-browser-mapping@2.9.19", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg=="],
410455
456 "birpc": ["birpc@4.0.0", "", {}, "sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw=="],
457
411458 "boolean": ["boolean@3.2.0", "", {}, "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw=="],
412459
413460 "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
......@@ -418,8 +465,6 @@
418465
419466 "bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="],
420467
421 "bundle-require": ["bundle-require@5.1.0", "", { "dependencies": { "load-tsconfig": "^0.2.3" }, "peerDependencies": { "esbuild": ">=0.18" } }, "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA=="],
422
423468 "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="],
424469
425470 "cacheable-lookup": ["cacheable-lookup@5.0.4", "", {}, "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA=="],
......@@ -432,9 +477,9 @@
432477
433478 "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="],
434479
435 "chai": ["chai@5.3.3", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw=="],
480 "chai": ["chai@6.2.2", "", {}, "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg=="],
436481
437 "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
482 "chalk": ["chalk@3.0.0", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg=="],
438483
439484 "character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="],
440485
......@@ -444,12 +489,6 @@
444489
445490 "character-reference-invalid": ["character-reference-invalid@2.0.1", "", {}, "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw=="],
446491
447 "check-error": ["check-error@2.1.3", "", {}, "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA=="],
448
449 "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
450
451 "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
452
453492 "clone-response": ["clone-response@1.0.3", "", { "dependencies": { "mimic-response": "^1.0.0" } }, "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA=="],
454493
455494 "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
......@@ -460,14 +499,6 @@
460499
461500 "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="],
462501
463 "commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="],
464
465 "concurrently": ["concurrently@9.2.1", "", { "dependencies": { "chalk": "4.1.2", "rxjs": "7.8.2", "shell-quote": "1.8.3", "supports-color": "8.1.1", "tree-kill": "1.2.2", "yargs": "17.7.2" }, "bin": { "conc": "dist/bin/concurrently.js", "concurrently": "dist/bin/concurrently.js" } }, "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng=="],
466
467 "confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
468
469 "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="],
470
471502 "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
472503
473504 "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
......@@ -478,8 +509,6 @@
478509
479510 "decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="],
480511
481 "deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="],
482
483512 "default-browser": ["default-browser@5.5.0", "", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw=="],
484513
485514 "default-browser-id": ["default-browser-id@5.0.1", "", {}, "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q=="],
......@@ -492,6 +521,8 @@
492521
493522 "define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="],
494523
524 "defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="],
525
495526 "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="],
496527
497528 "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="],
......@@ -502,6 +533,8 @@
502533
503534 "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="],
504535
536 "dts-resolver": ["dts-resolver@2.1.3", "", { "peerDependencies": { "oxc-resolver": ">=11.0.0" }, "optionalPeers": ["oxc-resolver"] }, "sha512-bihc7jPC90VrosXNzK0LTE2cuLP6jr0Ro8jk+kMugHReJVLIpHz/xadeq3MhuwyO4TD4OA3L1Q8pBBFRc08Tsw=="],
537
505538 "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
506539
507540 "electron": ["electron@33.4.11", "", { "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^20.9.0", "extract-zip": "^2.0.1" }, "bin": { "electron": "cli.js" } }, "sha512-xmdAs5QWRkInC7TpXGNvzo/7exojubk+72jn1oJL7keNeIlw7xNglf8TGtJtkR4rWC5FJq0oXiIXPS9BcK2Irg=="],
......@@ -510,7 +543,7 @@
510543
511544 "electronmon": ["electronmon@2.0.4", "", { "dependencies": { "chalk": "^3.0.0", "import-from": "^3.0.0", "runtime-required": "^1.1.0", "watchboy": "^0.4.3" }, "bin": { "electronmon": "bin/cli.js" } }, "sha512-u6eDrvUbqa+wsnMrhG2vHmo5neL1owLg2e5i1avGWcOb4rHsUf9lSfbs0FvfPsBNpLxxlPO98nrMhAGV+zw/fQ=="],
512545
513 "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
546 "empathic": ["empathic@2.0.0", "", {}, "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA=="],
514547
515548 "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="],
516549
......@@ -552,8 +585,6 @@
552585
553586 "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
554587
555 "fix-dts-default-cjs-exports": ["fix-dts-default-cjs-exports@1.0.1", "", { "dependencies": { "magic-string": "^0.30.17", "mlly": "^1.7.4", "rollup": "^4.34.8" } }, "sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg=="],
556
557588 "follow-redirects": ["follow-redirects@1.15.11", "", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="],
558589
559590 "form-data": ["form-data@4.0.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="],
......@@ -566,8 +597,6 @@
566597
567598 "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],
568599
569 "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
570
571600 "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
572601
573602 "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
......@@ -606,6 +635,8 @@
606635
607636 "highlight.js": ["highlight.js@11.11.1", "", {}, "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w=="],
608637
638 "hookable": ["hookable@6.0.1", "", {}, "sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw=="],
639
609640 "html-url-attributes": ["html-url-attributes@3.0.1", "", {}, "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ=="],
610641
611642 "http-cache-semantics": ["http-cache-semantics@4.2.0", "", {}, "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ=="],
......@@ -614,6 +645,8 @@
614645
615646 "import-from": ["import-from@3.0.0", "", { "dependencies": { "resolve-from": "^5.0.0" } }, "sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ=="],
616647
648 "import-without-cache": ["import-without-cache@0.2.5", "", {}, "sha512-B6Lc2s6yApwnD2/pMzFh/d5AVjdsDXjgkeJ766FmFuJELIGHNycKRj+l3A39yZPM4CchqNCB4RITEAYB1KUM6A=="],
649
617650 "inline-style-parser": ["inline-style-parser@0.2.7", "", {}, "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA=="],
618651
619652 "is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="],
......@@ -624,8 +657,6 @@
624657
625658 "is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="],
626659
627 "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
628
629660 "is-hexadecimal": ["is-hexadecimal@2.0.1", "", {}, "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg=="],
630661
631662 "is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="],
......@@ -640,9 +671,7 @@
640671
641672 "joi": ["joi@18.0.2", "", { "dependencies": { "@hapi/address": "^5.1.1", "@hapi/formula": "^3.0.2", "@hapi/hoek": "^11.0.7", "@hapi/pinpoint": "^2.0.1", "@hapi/tlds": "^1.1.1", "@hapi/topo": "^6.0.2", "@standard-schema/spec": "^1.0.0" } }, "sha512-RuCOQMIt78LWnktPoeBL0GErkNaJPTBGcYuyaBvUOQSpcpcLfWrHPPihYdOGbV5pam9VTWbeoF7TsGiHugcjGA=="],
642673
643 "joycon": ["joycon@3.1.1", "", {}, "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw=="],
644
645 "js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="],
674 "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
646675
647676 "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="],
648677
......@@ -656,35 +685,29 @@
656685
657686 "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
658687
659 "lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="],
660
661 "lightningcss-android-arm64": ["lightningcss-android-arm64@1.30.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="],
662
663 "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA=="],
688 "lightningcss": ["lightningcss@1.31.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.31.1", "lightningcss-darwin-arm64": "1.31.1", "lightningcss-darwin-x64": "1.31.1", "lightningcss-freebsd-x64": "1.31.1", "lightningcss-linux-arm-gnueabihf": "1.31.1", "lightningcss-linux-arm64-gnu": "1.31.1", "lightningcss-linux-arm64-musl": "1.31.1", "lightningcss-linux-x64-gnu": "1.31.1", "lightningcss-linux-x64-musl": "1.31.1", "lightningcss-win32-arm64-msvc": "1.31.1", "lightningcss-win32-x64-msvc": "1.31.1" } }, "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ=="],
664689
665 "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ=="],
690 "lightningcss-android-arm64": ["lightningcss-android-arm64@1.31.1", "", { "os": "android", "cpu": "arm64" }, "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg=="],
666691
667 "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA=="],
692 "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.31.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg=="],
668693
669 "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.2", "", { "os": "linux", "cpu": "arm" }, "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA=="],
694 "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.31.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA=="],
670695
671 "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A=="],
696 "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.31.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A=="],
672697
673 "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA=="],
698 "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.31.1", "", { "os": "linux", "cpu": "arm" }, "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g=="],
674699
675 "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w=="],
700 "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg=="],
676701
677 "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA=="],
702 "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg=="],
678703
679 "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ=="],
704 "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA=="],
680705
681 "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="],
706 "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA=="],
682707
683 "lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="],
708 "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.31.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w=="],
684709
685 "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="],
686
687 "load-tsconfig": ["load-tsconfig@0.2.5", "", {}, "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg=="],
710 "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.31.1", "", { "os": "win32", "cpu": "x64" }, "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw=="],
688711
689712 "lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="],
690713
......@@ -692,8 +715,6 @@
692715
693716 "longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="],
694717
695 "loupe": ["loupe@3.2.1", "", {}, "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ=="],
696
697718 "lowercase-keys": ["lowercase-keys@2.0.0", "", {}, "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA=="],
698719
699720 "lowlight": ["lowlight@3.3.0", "", { "dependencies": { "@types/hast": "^3.0.0", "devlop": "^1.0.0", "highlight.js": "~11.11.0" } }, "sha512-0JNhgFoPvP6U6lE/UdVsSq99tn6DhjjpAj5MxG49ewd2mOBVtwWYIT8ClyABhq198aXXODMU6Ox8DrGy/CpTZQ=="],
......@@ -806,12 +827,8 @@
806827
807828 "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
808829
809 "mlly": ["mlly@1.8.0", "", { "dependencies": { "acorn": "^8.15.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.1" } }, "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g=="],
810
811830 "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
812831
813 "mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="],
814
815832 "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
816833
817834 "node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="],
......@@ -820,10 +837,10 @@
820837
821838 "normalize-url": ["normalize-url@6.1.0", "", {}, "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A=="],
822839
823 "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
824
825840 "object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="],
826841
842 "obug": ["obug@2.1.1", "", {}, "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ=="],
843
827844 "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
828845
829846 "open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="],
......@@ -838,8 +855,6 @@
838855
839856 "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
840857
841 "pathval": ["pathval@2.0.1", "", {}, "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ=="],
842
843858 "pend": ["pend@1.2.0", "", {}, "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="],
844859
845860 "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
......@@ -848,14 +863,8 @@
848863
849864 "pify": ["pify@4.0.1", "", {}, "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="],
850865
851 "pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="],
852
853 "pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="],
854
855866 "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
856867
857 "postcss-load-config": ["postcss-load-config@6.0.1", "", { "dependencies": { "lilconfig": "^3.1.1" }, "peerDependencies": { "jiti": ">=1.21.0", "postcss": ">=8.0.9", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["jiti", "postcss", "tsx", "yaml"] }, "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g=="],
858
859868 "progress": ["progress@2.0.3", "", {}, "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="],
860869
861870 "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="],
......@@ -864,6 +873,8 @@
864873
865874 "pump": ["pump@3.0.3", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA=="],
866875
876 "quansync": ["quansync@1.0.0", "", {}, "sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA=="],
877
867878 "quick-lru": ["quick-lru@5.1.1", "", {}, "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA=="],
868879
869880 "react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="],
......@@ -872,9 +883,7 @@
872883
873884 "react-markdown": ["react-markdown@10.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "html-url-attributes": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "unified": "^11.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" }, "peerDependencies": { "@types/react": ">=18", "react": ">=18" } }, "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ=="],
874885
875 "react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="],
876
877 "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
886 "react-refresh": ["react-refresh@0.18.0", "", {}, "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw=="],
878887
879888 "rehype-highlight": ["rehype-highlight@7.0.2", "", { "dependencies": { "@types/hast": "^3.0.0", "hast-util-to-text": "^4.0.0", "lowlight": "^3.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-k158pK7wdC2qL3M5NcZROZ2tR/l7zOzjxXd5VGdcfIyoijjQqpHd3JKtYSBDpDZ38UI2WJWuFAtkMDxmx5kstA=="],
880889
......@@ -888,8 +897,6 @@
888897
889898 "remove-trailing-separator": ["remove-trailing-separator@1.1.0", "", {}, "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw=="],
890899
891 "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="],
892
893900 "resolve-alpn": ["resolve-alpn@1.2.1", "", {}, "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g=="],
894901
895902 "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="],
......@@ -900,6 +907,10 @@
900907
901908 "roarr": ["roarr@2.15.4", "", { "dependencies": { "boolean": "^3.0.1", "detect-node": "^2.0.4", "globalthis": "^1.0.1", "json-stringify-safe": "^5.0.1", "semver-compare": "^1.0.0", "sprintf-js": "^1.1.2" } }, "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A=="],
902909
910 "rolldown": ["rolldown@1.0.0-rc.3", "", { "dependencies": { "@oxc-project/types": "=0.112.0", "@rolldown/pluginutils": "1.0.0-rc.3" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-rc.3", "@rolldown/binding-darwin-arm64": "1.0.0-rc.3", "@rolldown/binding-darwin-x64": "1.0.0-rc.3", "@rolldown/binding-freebsd-x64": "1.0.0-rc.3", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.3", "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.3", "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.3", "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.3", "@rolldown/binding-linux-x64-musl": "1.0.0-rc.3", "@rolldown/binding-openharmony-arm64": "1.0.0-rc.3", "@rolldown/binding-wasm32-wasi": "1.0.0-rc.3", "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.3", "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.3" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-Po/YZECDOqVXjIXrtC5h++a5NLvKAQNrd9ggrIG3sbDfGO5BqTUsrI6l8zdniKRp3r5Tp/2JTrXqx4GIguFCMw=="],
911
912 "rolldown-plugin-dts": ["rolldown-plugin-dts@0.22.1", "", { "dependencies": { "@babel/generator": "8.0.0-rc.1", "@babel/helper-validator-identifier": "8.0.0-rc.1", "@babel/parser": "8.0.0-rc.1", "@babel/types": "8.0.0-rc.1", "ast-kit": "^3.0.0-beta.1", "birpc": "^4.0.0", "dts-resolver": "^2.1.3", "get-tsconfig": "^4.13.1", "obug": "^2.1.1" }, "peerDependencies": { "@ts-macro/tsc": "^0.3.6", "@typescript/native-preview": ">=7.0.0-dev.20250601.1", "rolldown": "^1.0.0-rc.3", "typescript": "^5.0.0", "vue-tsc": "~3.2.0" }, "optionalPeers": ["@ts-macro/tsc", "@typescript/native-preview", "typescript", "vue-tsc"] }, "sha512-5E0AiM5RSQhU6cjtkDFWH6laW4IrMu0j1Mo8x04Xo1ALHmaRMs9/7zej7P3RrryVHW/DdZAp85MA7Be55p0iUw=="],
913
903914 "rollup": ["rollup@4.57.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.57.1", "@rollup/rollup-android-arm64": "4.57.1", "@rollup/rollup-darwin-arm64": "4.57.1", "@rollup/rollup-darwin-x64": "4.57.1", "@rollup/rollup-freebsd-arm64": "4.57.1", "@rollup/rollup-freebsd-x64": "4.57.1", "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", "@rollup/rollup-linux-arm-musleabihf": "4.57.1", "@rollup/rollup-linux-arm64-gnu": "4.57.1", "@rollup/rollup-linux-arm64-musl": "4.57.1", "@rollup/rollup-linux-loong64-gnu": "4.57.1", "@rollup/rollup-linux-loong64-musl": "4.57.1", "@rollup/rollup-linux-ppc64-gnu": "4.57.1", "@rollup/rollup-linux-ppc64-musl": "4.57.1", "@rollup/rollup-linux-riscv64-gnu": "4.57.1", "@rollup/rollup-linux-riscv64-musl": "4.57.1", "@rollup/rollup-linux-s390x-gnu": "4.57.1", "@rollup/rollup-linux-x64-gnu": "4.57.1", "@rollup/rollup-linux-x64-musl": "4.57.1", "@rollup/rollup-openbsd-x64": "4.57.1", "@rollup/rollup-openharmony-arm64": "4.57.1", "@rollup/rollup-win32-arm64-msvc": "4.57.1", "@rollup/rollup-win32-ia32-msvc": "4.57.1", "@rollup/rollup-win32-x64-gnu": "4.57.1", "@rollup/rollup-win32-x64-msvc": "4.57.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A=="],
904915
905916 "run-applescript": ["run-applescript@7.1.0", "", {}, "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q=="],
......@@ -910,18 +921,14 @@
910921
911922 "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
912923
913 "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
924 "semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
914925
915926 "semver-compare": ["semver-compare@1.0.0", "", {}, "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow=="],
916927
917928 "serialize-error": ["serialize-error@7.0.1", "", { "dependencies": { "type-fest": "^0.13.1" } }, "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw=="],
918929
919 "shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="],
920
921930 "siginfo": ["siginfo@2.0.0", "", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="],
922931
923 "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="],
924
925932 "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
926933
927934 "space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="],
......@@ -932,23 +939,15 @@
932939
933940 "std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="],
934941
935 "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
936
937942 "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="],
938943
939 "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
940
941 "strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="],
942
943944 "style-to-js": ["style-to-js@1.1.21", "", { "dependencies": { "style-to-object": "1.0.14" } }, "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ=="],
944945
945946 "style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="],
946947
947 "sucrase": ["sucrase@3.35.1", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "tinyglobby": "^0.2.11", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw=="],
948
949948 "sumchecker": ["sumchecker@3.0.1", "", { "dependencies": { "debug": "^4.1.0" } }, "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg=="],
950949
951 "supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
950 "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
952951
953952 "t3": ["t3@workspace:apps/server"],
954953
......@@ -956,21 +955,15 @@
956955
957956 "tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="],
958957
959 "thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="],
960
961 "thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="],
962
963958 "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="],
964959
965 "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="],
960 "tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="],
966961
967962 "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
968963
969964 "tinypool": ["tinypool@2.1.0", "", {}, "sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw=="],
970965
971 "tinyrainbow": ["tinyrainbow@2.0.0", "", {}, "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw=="],
972
973 "tinyspy": ["tinyspy@4.0.4", "", {}, "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q=="],
966 "tinyrainbow": ["tinyrainbow@3.0.3", "", {}, "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q=="],
974967
975968 "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
976969
......@@ -980,12 +973,10 @@
980973
981974 "trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="],
982975
983 "ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="],
976 "tsdown": ["tsdown@0.20.3", "", { "dependencies": { "ansis": "^4.2.0", "cac": "^6.7.14", "defu": "^6.1.4", "empathic": "^2.0.0", "hookable": "^6.0.1", "import-without-cache": "^0.2.5", "obug": "^2.1.1", "picomatch": "^4.0.3", "rolldown": "1.0.0-rc.3", "rolldown-plugin-dts": "^0.22.1", "semver": "^7.7.3", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tree-kill": "^1.2.2", "unconfig-core": "^7.4.2", "unrun": "^0.2.27" }, "peerDependencies": { "@arethetypeswrong/core": "^0.18.1", "@vitejs/devtools": "*", "publint": "^0.3.0", "typescript": "^5.0.0", "unplugin-lightningcss": "^0.4.0", "unplugin-unused": "^0.5.0" }, "optionalPeers": ["@arethetypeswrong/core", "@vitejs/devtools", "publint", "typescript", "unplugin-lightningcss", "unplugin-unused"], "bin": { "tsdown": "dist/run.mjs" } }, "sha512-qWOUXSbe4jN8JZEgrkc/uhJpC8VN2QpNu3eZkBWwNuTEjc/Ik1kcc54ycfcQ5QPRHeu9OQXaLfCI3o7pEJgB2w=="],
984977
985978 "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
986979
987 "tsup": ["tsup@8.5.1", "", { "dependencies": { "bundle-require": "^5.1.0", "cac": "^6.7.14", "chokidar": "^4.0.3", "consola": "^3.4.0", "debug": "^4.4.0", "esbuild": "^0.27.0", "fix-dts-default-cjs-exports": "^1.0.0", "joycon": "^3.1.1", "picocolors": "^1.1.1", "postcss-load-config": "^6.0.1", "resolve-from": "^5.0.0", "rollup": "^4.34.8", "source-map": "^0.7.6", "sucrase": "^3.35.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.11", "tree-kill": "^1.2.2" }, "peerDependencies": { "@microsoft/api-extractor": "^7.36.0", "@swc/core": "^1", "postcss": "^8.4.12", "typescript": ">=4.5.0" }, "optionalPeers": ["@microsoft/api-extractor", "@swc/core", "postcss", "typescript"], "bin": { "tsup": "dist/cli-default.js", "tsup-node": "dist/cli-node.js" } }, "sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing=="],
988
989980 "tsx": ["tsx@4.21.0", "", { "dependencies": { "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw=="],
990981
991982 "turbo": ["turbo@2.8.3", "", { "optionalDependencies": { "turbo-darwin-64": "2.8.3", "turbo-darwin-arm64": "2.8.3", "turbo-linux-64": "2.8.3", "turbo-linux-arm64": "2.8.3", "turbo-windows-64": "2.8.3", "turbo-windows-arm64": "2.8.3" }, "bin": { "turbo": "bin/turbo" } }, "sha512-8Osxz5Tu/Dw2kb31EAY+nhq/YZ3wzmQSmYa1nIArqxgCAldxv9TPlrAiaBUDVnKA4aiPn0OFBD1ACcpc5VFOAQ=="],
......@@ -1006,7 +997,7 @@
1006997
1007998 "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
1008999
1009 "ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="],
1000 "unconfig-core": ["unconfig-core@7.4.2", "", { "dependencies": { "@quansync/fs": "^1.0.0", "quansync": "^1.0.0" } }, "sha512-VgPCvLWugINbXvMQDf8Jh0mlbvNjNC6eSUziHsBCMpxR05OPrNrvDnyatdMjRgcHaaNsCqz+wjNXxNw1kRLHUg=="],
10101001
10111002 "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
10121003
......@@ -1028,17 +1019,17 @@
10281019
10291020 "unixify": ["unixify@1.0.0", "", { "dependencies": { "normalize-path": "^2.1.1" } }, "sha512-6bc58dPYhCMHHuwxldQxO3RRNZ4eCogZ/st++0+fcC1nr0jiGUtAdBJ2qzmLQWSxbtz42pWt4QQMiZ9HvZf5cg=="],
10301021
1022 "unrun": ["unrun@0.2.27", "", { "dependencies": { "rolldown": "1.0.0-rc.3" }, "peerDependencies": { "synckit": "^0.11.11" }, "optionalPeers": ["synckit"], "bin": { "unrun": "dist/cli.mjs" } }, "sha512-Mmur1UJpIbfxasLOhPRvox/QS4xBiDii71hMP7smfRthGcwFL2OAmYRgduLANOAU4LUkvVamuP+02U+c90jlrw=="],
1023
10311024 "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="],
10321025
10331026 "vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="],
10341027
10351028 "vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="],
10361029
1037 "vite": ["vite@6.4.1", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="],
1038
1039 "vite-node": ["vite-node@3.2.4", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.1", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg=="],
1030 "vite": ["vite@8.0.0-beta.13", "", { "dependencies": { "@oxc-project/runtime": "0.112.0", "fdir": "^6.5.0", "lightningcss": "^1.31.1", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rolldown": "1.0.0-rc.3", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.0.0-alpha.24", "esbuild": "^0.27.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-7s/rfpYOAo7WUHh9irzaGjhhKb12hGv0BpDegAMV5A391wdyvM45WtX6VMV7hvEtZF2j/QtpDpR6ldXI3GgARQ=="],
10401031
1041 "vitest": ["vitest@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", "@vitest/mocker": "3.2.4", "@vitest/pretty-format": "^3.2.4", "@vitest/runner": "3.2.4", "@vitest/snapshot": "3.2.4", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "debug": "^4.4.1", "expect-type": "^1.2.1", "magic-string": "^0.30.17", "pathe": "^2.0.3", "picomatch": "^4.0.2", "std-env": "^3.9.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.14", "tinypool": "^1.1.1", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", "vite-node": "3.2.4", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "@vitest/browser": "3.2.4", "@vitest/ui": "3.2.4", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@types/debug", "@types/node", "@vitest/browser", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A=="],
1032 "vitest": ["vitest@4.0.18", "", { "dependencies": { "@vitest/expect": "4.0.18", "@vitest/mocker": "4.0.18", "@vitest/pretty-format": "4.0.18", "@vitest/runner": "4.0.18", "@vitest/snapshot": "4.0.18", "@vitest/spy": "4.0.18", "@vitest/utils": "4.0.18", "es-module-lexer": "^1.7.0", "expect-type": "^1.2.2", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^3.10.0", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.0.3", "vite": "^6.0.0 || ^7.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.0.18", "@vitest/browser-preview": "4.0.18", "@vitest/browser-webdriverio": "4.0.18", "@vitest/ui": "4.0.18", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ=="],
10421033
10431034 "wait-on": ["wait-on@8.0.5", "", { "dependencies": { "axios": "^1.12.1", "joi": "^18.0.1", "lodash": "^4.17.21", "minimist": "^1.2.8", "rxjs": "^7.8.2" }, "bin": { "wait-on": "bin/wait-on" } }, "sha512-J3WlS0txVHkhLRb2FsmRg3dkMTCV1+M6Xra3Ho7HzZDHpE7DCOnoSoCJsZotrmW3uRMhvIJGSKUKrh/MeF4iag=="],
10441035
......@@ -1046,32 +1037,50 @@
10461037
10471038 "why-is-node-running": ["why-is-node-running@2.3.0", "", { "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": { "why-is-node-running": "cli.js" } }, "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w=="],
10481039
1049 "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
1050
10511040 "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
10521041
10531042 "ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="],
10541043
10551044 "wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="],
10561045
1057 "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
1058
10591046 "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
10601047
1061 "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
1062
1063 "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
1064
10651048 "yauzl": ["yauzl@2.10.0", "", { "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g=="],
10661049
10671050 "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
10681051
10691052 "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
10701053
1071 "@babel/code-frame/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
1054 "@babel/code-frame/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
1055
1056 "@babel/core/@babel/generator": ["@babel/generator@7.29.1", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw=="],
1057
1058 "@babel/core/@babel/parser": ["@babel/parser@7.29.0", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww=="],
1059
1060 "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
1061
1062 "@babel/generator/@babel/types": ["@babel/types@8.0.0-rc.1", "", { "dependencies": { "@babel/helper-string-parser": "^8.0.0-rc.1", "@babel/helper-validator-identifier": "^8.0.0-rc.1" } }, "sha512-ubmJ6TShyaD69VE9DQrlXcdkvJbmwWPB8qYj0H2kaJi29O7vJT9ajSdBd2W8CG34pwL9pYA74fi7RHC1qbLoVQ=="],
1063
1064 "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
1065
1066 "@babel/helper-module-transforms/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
1067
1068 "@babel/parser/@babel/types": ["@babel/types@8.0.0-rc.1", "", { "dependencies": { "@babel/helper-string-parser": "^8.0.0-rc.1", "@babel/helper-validator-identifier": "^8.0.0-rc.1" } }, "sha512-ubmJ6TShyaD69VE9DQrlXcdkvJbmwWPB8qYj0H2kaJi29O7vJT9ajSdBd2W8CG34pwL9pYA74fi7RHC1qbLoVQ=="],
1069
1070 "@babel/template/@babel/parser": ["@babel/parser@7.29.0", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww=="],
1071
1072 "@babel/traverse/@babel/generator": ["@babel/generator@7.29.1", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw=="],
1073
1074 "@babel/traverse/@babel/parser": ["@babel/parser@7.29.0", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww=="],
1075
1076 "@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
1077
1078 "@electron/get/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
10721079
10731080 "@tailwindcss/node/jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
10741081
1082 "@tailwindcss/node/lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="],
1083
10751084 "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="],
10761085
10771086 "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="],
......@@ -1084,15 +1093,17 @@
10841093
10851094 "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
10861095
1087 "chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
1096 "@tailwindcss/vite/vite": ["vite@6.4.1", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="],
10881097
1089 "clone-response/mimic-response": ["mimic-response@1.0.1", "", {}, "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="],
1098 "@types/babel__core/@babel/parser": ["@babel/parser@7.29.0", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww=="],
10901099
1091 "electron/@types/node": ["@types/node@20.19.33", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw=="],
1100 "@types/babel__template/@babel/parser": ["@babel/parser@7.29.0", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww=="],
10921101
1093 "electronmon/chalk": ["chalk@3.0.0", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg=="],
1102 "@vitejs/plugin-react/vite": ["vite@6.4.1", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="],
10941103
1095 "global-agent/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
1104 "clone-response/mimic-response": ["mimic-response@1.0.1", "", {}, "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="],
1105
1106 "electron/@types/node": ["@types/node@20.19.33", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw=="],
10961107
10971108 "mdast-util-find-and-replace/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
10981109
......@@ -1100,62 +1111,198 @@
11001111
11011112 "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
11021113
1103 "vite/esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="],
1114 "rolldown-plugin-dts/@babel/types": ["@babel/types@8.0.0-rc.1", "", { "dependencies": { "@babel/helper-string-parser": "^8.0.0-rc.1", "@babel/helper-validator-identifier": "^8.0.0-rc.1" } }, "sha512-ubmJ6TShyaD69VE9DQrlXcdkvJbmwWPB8qYj0H2kaJi29O7vJT9ajSdBd2W8CG34pwL9pYA74fi7RHC1qbLoVQ=="],
1115
1116 "vitest/vite": ["vite@6.4.1", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="],
1117
1118 "@babel/generator/@babel/types/@babel/helper-string-parser": ["@babel/helper-string-parser@8.0.0-rc.1", "", {}, "sha512-vi/pfmbrOtQmqgfboaBhaCU50G7mcySVu69VU8z+lYoPPB6WzI9VgV7WQfL908M4oeSH5fDkmoupIqoE0SdApw=="],
1119
1120 "@babel/parser/@babel/types/@babel/helper-string-parser": ["@babel/helper-string-parser@8.0.0-rc.1", "", {}, "sha512-vi/pfmbrOtQmqgfboaBhaCU50G7mcySVu69VU8z+lYoPPB6WzI9VgV7WQfL908M4oeSH5fDkmoupIqoE0SdApw=="],
1121
1122 "@tailwindcss/node/lightningcss/lightningcss-android-arm64": ["lightningcss-android-arm64@1.30.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="],
1123
1124 "@tailwindcss/node/lightningcss/lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA=="],
1125
1126 "@tailwindcss/node/lightningcss/lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ=="],
1127
1128 "@tailwindcss/node/lightningcss/lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA=="],
1129
1130 "@tailwindcss/node/lightningcss/lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.2", "", { "os": "linux", "cpu": "arm" }, "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA=="],
1131
1132 "@tailwindcss/node/lightningcss/lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A=="],
1133
1134 "@tailwindcss/node/lightningcss/lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA=="],
1135
1136 "@tailwindcss/node/lightningcss/lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w=="],
1137
1138 "@tailwindcss/node/lightningcss/lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA=="],
1139
1140 "@tailwindcss/node/lightningcss/lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ=="],
1141
1142 "@tailwindcss/node/lightningcss/lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="],
1143
1144 "@tailwindcss/vite/vite/esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="],
1145
1146 "@vitejs/plugin-react/vite/esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="],
1147
1148 "rolldown-plugin-dts/@babel/types/@babel/helper-string-parser": ["@babel/helper-string-parser@8.0.0-rc.1", "", {}, "sha512-vi/pfmbrOtQmqgfboaBhaCU50G7mcySVu69VU8z+lYoPPB6WzI9VgV7WQfL908M4oeSH5fDkmoupIqoE0SdApw=="],
1149
1150 "vitest/vite/esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="],
1151
1152 "@tailwindcss/vite/vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="],
1153
1154 "@tailwindcss/vite/vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="],
1155
1156 "@tailwindcss/vite/vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="],
1157
1158 "@tailwindcss/vite/vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="],
1159
1160 "@tailwindcss/vite/vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="],
1161
1162 "@tailwindcss/vite/vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="],
1163
1164 "@tailwindcss/vite/vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="],
1165
1166 "@tailwindcss/vite/vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="],
1167
1168 "@tailwindcss/vite/vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="],
1169
1170 "@tailwindcss/vite/vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="],
1171
1172 "@tailwindcss/vite/vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="],
1173
1174 "@tailwindcss/vite/vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="],
1175
1176 "@tailwindcss/vite/vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="],
1177
1178 "@tailwindcss/vite/vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="],
1179
1180 "@tailwindcss/vite/vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="],
1181
1182 "@tailwindcss/vite/vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="],
1183
1184 "@tailwindcss/vite/vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="],
1185
1186 "@tailwindcss/vite/vite/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="],
1187
1188 "@tailwindcss/vite/vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="],
1189
1190 "@tailwindcss/vite/vite/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="],
1191
1192 "@tailwindcss/vite/vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="],
1193
1194 "@tailwindcss/vite/vite/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="],
1195
1196 "@tailwindcss/vite/vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="],
1197
1198 "@tailwindcss/vite/vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="],
1199
1200 "@tailwindcss/vite/vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="],
1201
1202 "@tailwindcss/vite/vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="],
1203
1204 "@vitejs/plugin-react/vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="],
1205
1206 "@vitejs/plugin-react/vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="],
1207
1208 "@vitejs/plugin-react/vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="],
1209
1210 "@vitejs/plugin-react/vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="],
1211
1212 "@vitejs/plugin-react/vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="],
1213
1214 "@vitejs/plugin-react/vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="],
1215
1216 "@vitejs/plugin-react/vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="],
1217
1218 "@vitejs/plugin-react/vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="],
1219
1220 "@vitejs/plugin-react/vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="],
1221
1222 "@vitejs/plugin-react/vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="],
1223
1224 "@vitejs/plugin-react/vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="],
1225
1226 "@vitejs/plugin-react/vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="],
1227
1228 "@vitejs/plugin-react/vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="],
1229
1230 "@vitejs/plugin-react/vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="],
1231
1232 "@vitejs/plugin-react/vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="],
1233
1234 "@vitejs/plugin-react/vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="],
1235
1236 "@vitejs/plugin-react/vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="],
1237
1238 "@vitejs/plugin-react/vite/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="],
1239
1240 "@vitejs/plugin-react/vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="],
1241
1242 "@vitejs/plugin-react/vite/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="],
1243
1244 "@vitejs/plugin-react/vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="],
1245
1246 "@vitejs/plugin-react/vite/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="],
1247
1248 "@vitejs/plugin-react/vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="],
1249
1250 "@vitejs/plugin-react/vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="],
11041251
1105 "vitest/tinypool": ["tinypool@1.1.1", "", {}, "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg=="],
1252 "@vitejs/plugin-react/vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="],
11061253
1107 "electronmon/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
1254 "@vitejs/plugin-react/vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="],
11081255
1109 "vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="],
1256 "vitest/vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="],
11101257
1111 "vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="],
1258 "vitest/vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="],
11121259
1113 "vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="],
1260 "vitest/vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="],
11141261
1115 "vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="],
1262 "vitest/vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="],
11161263
1117 "vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="],
1264 "vitest/vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="],
11181265
1119 "vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="],
1266 "vitest/vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="],
11201267
1121 "vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="],
1268 "vitest/vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="],
11221269
1123 "vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="],
1270 "vitest/vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="],
11241271
1125 "vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="],
1272 "vitest/vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="],
11261273
1127 "vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="],
1274 "vitest/vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="],
11281275
1129 "vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="],
1276 "vitest/vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="],
11301277
1131 "vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="],
1278 "vitest/vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="],
11321279
1133 "vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="],
1280 "vitest/vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="],
11341281
1135 "vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="],
1282 "vitest/vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="],
11361283
1137 "vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="],
1284 "vitest/vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="],
11381285
1139 "vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="],
1286 "vitest/vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="],
11401287
1141 "vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="],
1288 "vitest/vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="],
11421289
1143 "vite/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="],
1290 "vitest/vite/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="],
11441291
1145 "vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="],
1292 "vitest/vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="],
11461293
1147 "vite/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="],
1294 "vitest/vite/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="],
11481295
1149 "vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="],
1296 "vitest/vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="],
11501297
1151 "vite/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="],
1298 "vitest/vite/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="],
11521299
1153 "vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="],
1300 "vitest/vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="],
11541301
1155 "vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="],
1302 "vitest/vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="],
11561303
1157 "vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="],
1304 "vitest/vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="],
11581305
1159 "vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="],
1306 "vitest/vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="],
11601307 }
11611308}
package.json+9-9
......@@ -7,26 +7,26 @@
77 ],
88 "scripts": {
99 "dev": "T3CODE_LOG_WS_EVENTS=1 VITE_WS_URL=ws://localhost:3773 turbo run dev --ui=tui --filter=@t3tools/contracts --filter=@t3tools/web --filter=t3 --parallel",
10 "dev:server": "bun run build:contracts && bun run --cwd apps/server dev",
11 "dev:web": "VITE_WS_URL=ws://localhost:3773 bun run --cwd apps/web dev",
12 "dev:desktop": "bun run --cwd apps/desktop dev",
13 "start": "node apps/server/dist/index.js",
14 "start:desktop": "bun run --cwd apps/desktop start",
10 "dev:server": "turbo run dev --filter=t3",
11 "dev:web": "VITE_WS_URL=ws://localhost:3773 turbo run dev --filter=@t3tools/web",
12 "dev:desktop": "turbo run dev --filter=@t3tools/desktop --filter=@t3tools/web --parallel",
13 "start": "turbo run start --filter=t3",
14 "start:desktop": "turbo run start --filter=@t3tools/desktop",
1515 "build": "turbo run build",
16 "build:desktop": "bun run build:contracts && bun run --cwd apps/web build && bun run --cwd apps/server build && bun run --cwd apps/desktop build",
16 "build:desktop": "turbo run build --filter=@t3tools/desktop --filter=t3",
1717 "typecheck": "turbo run typecheck",
1818 "lint": "oxlint --report-unused-disable-directives",
1919 "test": "turbo run test",
20 "test:desktop-smoke": "bun run --cwd apps/desktop smoke-test",
20 "test:desktop-smoke": "turbo run smoke-test --filter=@t3tools/desktop",
2121 "fmt": "oxfmt",
22 "build:contracts": "bun run --cwd packages/contracts build"
22 "build:contracts": "turbo run build --filter=@t3tools/contracts"
2323 },
2424 "devDependencies": {
2525 "oxfmt": "^0.28.0",
2626 "oxlint": "^1.43.0",
2727 "turbo": "^2.3.3",
2828 "typescript": "^5.7.3",
29 "vitest": "^3.0.0"
29 "vitest": "^4.0.0"
3030 },
3131 "engines": {
3232 "bun": ">=1.3.9"
packages/contracts/package.json+5-5
......@@ -7,18 +7,18 @@
77 ],
88 "type": "module",
99 "main": "./dist/index.cjs",
10 "module": "./dist/index.js",
10 "module": "./dist/index.mjs",
1111 "types": "./src/index.ts",
1212 "exports": {
1313 ".": {
1414 "types": "./src/index.ts",
15 "import": "./dist/index.js",
15 "import": "./dist/index.mjs",
1616 "require": "./dist/index.cjs"
1717 }
1818 },
1919 "scripts": {
20 "dev": "tsup src/index.ts --format esm,cjs --dts --watch --clean",
21 "build": "tsup src/index.ts --format esm,cjs --dts --clean",
20 "dev": "tsdown src/index.ts --format esm,cjs --dts --watch --clean",
21 "build": "tsdown src/index.ts --format esm,cjs --dts --clean",
2222 "typecheck": "tsc --noEmit",
2323 "test": "vitest run"
2424 },
......@@ -26,7 +26,7 @@
2626 "zod": "^3.24.1"
2727 },
2828 "devDependencies": {
29 "tsup": "^8.3.5",
29 "tsdown": "^0.20.3",
3030 "typescript": "^5.7.3"
3131 }
3232}
packages/contracts/src/git.ts created+69
......@@ -0,0 +1,69 @@
1import { z } from "zod";
2
3// ── Input schemas ──
4
5export const gitListBranchesInputSchema = z.object({
6 cwd: z.string().min(1),
7});
8
9export const gitCreateWorktreeInputSchema = z.object({
10 cwd: z.string().min(1),
11 /** Base branch to create the worktree from. */
12 branch: z.string().min(1),
13 /** New branch name to create in the worktree. */
14 newBranch: z.string().min(1),
15 path: z.string().min(1).optional(),
16});
17
18export const gitRemoveWorktreeInputSchema = z.object({
19 cwd: z.string().min(1),
20 path: z.string().min(1),
21});
22
23export const gitCreateBranchInputSchema = z.object({
24 cwd: z.string().min(1),
25 branch: z.string().min(1),
26});
27
28export const gitCheckoutInputSchema = z.object({
29 cwd: z.string().min(1),
30 branch: z.string().min(1),
31});
32
33export const gitInitInputSchema = z.object({
34 cwd: z.string().min(1),
35});
36
37// ── Output schemas ──
38
39export const gitBranchSchema = z.object({
40 name: z.string().min(1),
41 current: z.boolean(),
42 isDefault: z.boolean(),
43 worktreePath: z.string().min(1).nullable(),
44});
45
46export const gitWorktreeSchema = z.object({
47 path: z.string().min(1),
48 branch: z.string().min(1),
49});
50
51// ── Types ──
52
53export type GitListBranchesInput = z.infer<typeof gitListBranchesInputSchema>;
54export type GitBranch = z.infer<typeof gitBranchSchema>;
55export type GitCreateWorktreeInput = z.infer<typeof gitCreateWorktreeInputSchema>;
56export type GitWorktree = z.infer<typeof gitWorktreeSchema>;
57export type GitRemoveWorktreeInput = z.infer<typeof gitRemoveWorktreeInputSchema>;
58export type GitCreateBranchInput = z.infer<typeof gitCreateBranchInputSchema>;
59export type GitCheckoutInput = z.infer<typeof gitCheckoutInputSchema>;
60export type GitInitInput = z.infer<typeof gitInitInputSchema>;
61
62export interface GitListBranchesResult {
63 branches: GitBranch[];
64 isRepo: boolean;
65}
66
67export interface GitCreateWorktreeResult {
68 worktree: GitWorktree;
69}
packages/contracts/src/index.ts+1
......@@ -6,3 +6,4 @@ export * from "./provider";
66export * from "./model";
77export * from "./ws";
88export * from "./project";
9export * from "./git";
packages/contracts/src/ipc.ts+18
......@@ -1,4 +1,14 @@
11import type { AgentConfig, AgentExit, OutputChunk } from "./agent";
2import type {
3 GitCheckoutInput,
4 GitCreateBranchInput,
5 GitCreateWorktreeInput,
6 GitCreateWorktreeResult,
7 GitInitInput,
8 GitListBranchesInput,
9 GitListBranchesResult,
10 GitRemoveWorktreeInput,
11} from "./git";
212import type {
313 ProviderEvent,
414 ProviderInterruptTurnInput,
......@@ -62,6 +72,14 @@ export interface NativeApi {
6272 shell: {
6373 openInEditor: (cwd: string, editor: EditorId) => Promise<void>;
6474 };
75 git: {
76 listBranches: (input: GitListBranchesInput) => Promise<GitListBranchesResult>;
77 createWorktree: (input: GitCreateWorktreeInput) => Promise<GitCreateWorktreeResult>;
78 removeWorktree: (input: GitRemoveWorktreeInput) => Promise<void>;
79 createBranch: (input: GitCreateBranchInput) => Promise<void>;
80 checkout: (input: GitCheckoutInput) => Promise<void>;
81 init: (input: GitInitInput) => Promise<void>;
82 };
6583 contextMenu: {
6684 show: <T extends string>(
6785 items: readonly { id: T; label: string }[],
packages/contracts/src/provider.ts+6-21
......@@ -83,12 +83,7 @@ export const providerRespondToRequestInputSchema = z.object({
8383 decision: providerApprovalDecisionSchema,
8484});
8585
86export const providerEventKindSchema = z.enum([
87 "session",
88 "notification",
89 "request",
90 "error",
91]);
86export const providerEventKindSchema = z.enum(["session", "notification", "request", "error"]);
9287
9388export const providerEventSchema = z.object({
9489 id: z.string().min(1),
......@@ -111,24 +106,14 @@ export type ProviderKind = z.infer<typeof providerKindSchema>;
111106export type ProviderApprovalPolicy = z.infer<typeof providerApprovalPolicySchema>;
112107export type ProviderSandboxMode = z.infer<typeof providerSandboxModeSchema>;
113108export type ProviderRequestKind = z.infer<typeof providerRequestKindSchema>;
114export type ProviderApprovalDecision = z.infer<
115 typeof providerApprovalDecisionSchema
116>;
109export type ProviderApprovalDecision = z.infer<typeof providerApprovalDecisionSchema>;
117110export type ProviderSessionStatus = z.infer<typeof providerSessionStatusSchema>;
118111export type ProviderSession = z.infer<typeof providerSessionSchema>;
119112export type ProviderSessionStartInput = z.input<typeof providerSessionStartInputSchema>;
120113export type ProviderSendTurnInput = z.input<typeof providerSendTurnInputSchema>;
121export type ProviderTurnStartResult = z.infer<
122 typeof providerTurnStartResultSchema
123>;
124export type ProviderInterruptTurnInput = z.input<
125 typeof providerInterruptTurnInputSchema
126>;
127export type ProviderStopSessionInput = z.input<
128 typeof providerStopSessionInputSchema
129>;
130export type ProviderRespondToRequestInput = z.input<
131 typeof providerRespondToRequestInputSchema
132>;
114export type ProviderTurnStartResult = z.infer<typeof providerTurnStartResultSchema>;
115export type ProviderInterruptTurnInput = z.input<typeof providerInterruptTurnInputSchema>;
116export type ProviderStopSessionInput = z.input<typeof providerStopSessionInputSchema>;
117export type ProviderRespondToRequestInput = z.input<typeof providerRespondToRequestInputSchema>;
133118export type ProviderEventKind = z.infer<typeof providerEventKindSchema>;
134119export type ProviderEvent = z.infer<typeof providerEventSchema>;
packages/contracts/src/ws.ts+8
......@@ -19,6 +19,14 @@ export const WS_METHODS = {
1919 // Shell methods
2020 shellOpenInEditor: "shell.openInEditor",
2121
22 // Git methods
23 gitListBranches: "git.listBranches",
24 gitCreateWorktree: "git.createWorktree",
25 gitRemoveWorktree: "git.removeWorktree",
26 gitCreateBranch: "git.createBranch",
27 gitCheckout: "git.checkout",
28 gitInit: "git.init",
29
2230 // Server meta
2331 serverGetConfig: "server.getConfig",
2432} as const;
vitest.config.ts+11-1
......@@ -1,3 +1,13 @@
1import * as path from "node:path";
12import { defineConfig } from "vitest/config";
23
3export default defineConfig({});
4export default defineConfig({
5 resolve: {
6 alias: [
7 {
8 find: /^@t3tools\/contracts$/,
9 replacement: path.resolve(import.meta.dirname, "./packages/contracts/src/index.ts"),
10 },
11 ],
12 },
13});