diff --git a/apps/web/package.json b/apps/web/package.json
index f847cc4..170457b 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -19,14 +19,12 @@
"@sketchi/backend": "workspace:*",
"@sketchi/env": "workspace:*",
"@sketchi/shared": "workspace:*",
- "@tanstack/react-form": "^1.28.3",
"@vercel/analytics": "^1.6.1",
"@workos-inc/authkit-nextjs": "^2.15.0",
"babel-plugin-react-compiler": "^1.0.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"convex": "catalog:",
- "dotenv": "catalog:",
"fractional-indexing": "^3.2.0",
"jszip": "^3.10.1",
"lucide-react": "^0.575.0",
@@ -44,8 +42,7 @@
"devDependencies": {
"@sketchi/config": "workspace:*",
"@tailwindcss/postcss": "^4.2.0",
- "@types/jszip": "^3.4.1",
- "@types/node": "^25.3.0",
+ "@types/node": "^25.6.0",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"tailwindcss": "^4.2.0",
diff --git a/apps/web/src/components/diagram-studio/diagram-list-item.tsx b/apps/web/src/components/diagram-studio/diagram-list-item.tsx
index b0d4cff..ce1a2f1 100644
--- a/apps/web/src/components/diagram-studio/diagram-list-item.tsx
+++ b/apps/web/src/components/diagram-studio/diagram-list-item.tsx
@@ -306,9 +306,9 @@ export function DiagramListItem({
Created {createdLabel}
) : null}
- {item.latestSceneVersion !== null ? (
+ {item.latestSceneVersion === null ? null : (
v{item.latestSceneVersion}
- ) : null}
+ )}
{originLabel}
diff --git a/apps/web/src/components/loader.tsx b/apps/web/src/components/loader.tsx
deleted file mode 100644
index e17ec79..0000000
--- a/apps/web/src/components/loader.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import { Loader2 } from "lucide-react";
-
-export default function Loader() {
- return (
-
-
-
- );
-}
diff --git a/apps/web/src/components/ui/card.tsx b/apps/web/src/components/ui/card.tsx
index f243586..c81d515 100644
--- a/apps/web/src/components/ui/card.tsx
+++ b/apps/web/src/components/ui/card.tsx
@@ -94,10 +94,10 @@ function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
export {
Card,
- CardHeader,
- CardFooter,
- CardTitle,
CardAction,
- CardDescription,
CardContent,
+ CardDescription,
+ CardFooter,
+ CardHeader,
+ CardTitle,
};
diff --git a/apps/web/src/components/ui/dropdown-menu.tsx b/apps/web/src/components/ui/dropdown-menu.tsx
index 39d8c69..69fa68b 100644
--- a/apps/web/src/components/ui/dropdown-menu.tsx
+++ b/apps/web/src/components/ui/dropdown-menu.tsx
@@ -245,18 +245,18 @@ function DropdownMenuShortcut({
export {
DropdownMenu,
- DropdownMenuPortal,
- DropdownMenuTrigger,
+ DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuGroup,
- DropdownMenuLabel,
DropdownMenuItem,
- DropdownMenuCheckboxItem,
+ DropdownMenuLabel,
+ DropdownMenuPortal,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuSub,
- DropdownMenuSubTrigger,
DropdownMenuSubContent,
+ DropdownMenuSubTrigger,
+ DropdownMenuTrigger,
};
diff --git a/apps/web/src/components/ui/skeleton.tsx b/apps/web/src/components/ui/skeleton.tsx
deleted file mode 100644
index 155a140..0000000
--- a/apps/web/src/components/ui/skeleton.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import { cn } from "@/lib/utils";
-
-function Skeleton({
- className,
- ...props
-}: React.HTMLAttributes) {
- return (
-
- );
-}
-
-export { Skeleton };
diff --git a/bun.lock b/bun.lock
index 2c50e27..51ecd32 100644
--- a/bun.lock
+++ b/bun.lock
@@ -4,17 +4,12 @@
"workspaces": {
"": {
"name": "sketchi",
- "dependencies": {
- "@sketchi/env": "workspace:*",
- "dotenv": "^17.3.1",
- "zod": "^4.3.6",
- },
"devDependencies": {
- "@biomejs/biome": "2.4.4",
+ "@biomejs/biome": "2.4.12",
"@sketchi/config": "workspace:*",
- "@types/bun": "^1.3.9",
- "@types/node": "^25.3.0",
- "turbo": "^2.8.10",
+ "@types/bun": "^1.3.12",
+ "@types/node": "^25.6.0",
+ "turbo": "^2.9.6",
"typescript": "^5.9.3",
"ultracite": "7.2.3",
},
@@ -33,14 +28,12 @@
"@sketchi/backend": "workspace:*",
"@sketchi/env": "workspace:*",
"@sketchi/shared": "workspace:*",
- "@tanstack/react-form": "^1.28.3",
"@vercel/analytics": "^1.6.1",
"@workos-inc/authkit-nextjs": "^2.15.0",
"babel-plugin-react-compiler": "^1.0.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"convex": "catalog:",
- "dotenv": "catalog:",
"fractional-indexing": "^3.2.0",
"jszip": "^3.10.1",
"lucide-react": "^0.575.0",
@@ -58,8 +51,7 @@
"devDependencies": {
"@sketchi/config": "workspace:*",
"@tailwindcss/postcss": "^4.2.0",
- "@types/jszip": "^3.4.1",
- "@types/node": "^25.3.0",
+ "@types/node": "^25.6.0",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"tailwindcss": "^4.2.0",
@@ -92,7 +84,7 @@
"devDependencies": {
"@edge-runtime/vm": "^5.0.0",
"@sketchi/config": "workspace:*",
- "@types/node": "^25.3.0",
+ "@types/node": "^25.6.0",
"@types/pako": "^2.0.4",
"convex-test": "^0.0.41",
"typescript": "catalog:",
@@ -108,7 +100,6 @@
"version": "0.0.0",
"dependencies": {
"@t3-oss/env-nextjs": "^0.13.10",
- "dotenv": "catalog:",
"zod": "catalog:",
},
"devDependencies": {
@@ -118,13 +109,13 @@
},
"packages/opencode-excalidraw": {
"name": "@sketchi-app/opencode-excalidraw",
- "version": "0.0.7",
+ "version": "0.0.9",
"dependencies": {
"playwright": "^1.58.2",
},
"devDependencies": {
"@opencode-ai/plugin": "1.2.10",
- "@types/node": "^25.3.0",
+ "@types/node": "^25.6.0",
"bun-types": "1.3.9",
"typescript": "^5.9.3",
},
@@ -150,20 +141,19 @@
"dependencies": {
"@browserbasehq/stagehand": "^3.0.8",
"@sketchi/shared": "workspace:*",
- "convex": "^1.32.0",
- "dotenv": "^17.3.1",
- "pako": "^2.1.0",
+ "dotenv": "catalog:",
},
"devDependencies": {
"@playwright/test": "^1.58.2",
- "@types/bun": "latest",
+ "@types/bun": "^1.3.12",
+ "bun-types": "1.3.9",
"rrweb-player": "1.0.0-alpha.4",
},
},
},
"catalog": {
"convex": "^1.31.7",
- "dotenv": "^17.2.4",
+ "dotenv": "^17.4.2",
"typescript": "^5",
"zod": "^4.1.13",
},
@@ -272,23 +262,23 @@
"@base-ui/utils": ["@base-ui/utils@0.2.5", "", { "dependencies": { "@babel/runtime": "^7.28.6", "@floating-ui/utils": "^0.2.10", "reselect": "^5.1.1", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "@types/react": "^17 || ^18 || ^19", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@types/react"] }, "sha512-oYC7w0gp76RI5MxprlGLV0wze0SErZaRl3AAkeP3OnNB/UBMb6RqNf6ZSIlxOc9Qp68Ab3C2VOcJQyRs7Xc7Vw=="],
- "@biomejs/biome": ["@biomejs/biome@2.4.4", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.4", "@biomejs/cli-darwin-x64": "2.4.4", "@biomejs/cli-linux-arm64": "2.4.4", "@biomejs/cli-linux-arm64-musl": "2.4.4", "@biomejs/cli-linux-x64": "2.4.4", "@biomejs/cli-linux-x64-musl": "2.4.4", "@biomejs/cli-win32-arm64": "2.4.4", "@biomejs/cli-win32-x64": "2.4.4" }, "bin": { "biome": "bin/biome" } }, "sha512-tigwWS5KfJf0cABVd52NVaXyAVv4qpUXOWJ1rxFL8xF1RVoeS2q/LK+FHgYoKMclJCuRoCWAPy1IXaN9/mS61Q=="],
+ "@biomejs/biome": ["@biomejs/biome@2.4.12", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.12", "@biomejs/cli-darwin-x64": "2.4.12", "@biomejs/cli-linux-arm64": "2.4.12", "@biomejs/cli-linux-arm64-musl": "2.4.12", "@biomejs/cli-linux-x64": "2.4.12", "@biomejs/cli-linux-x64-musl": "2.4.12", "@biomejs/cli-win32-arm64": "2.4.12", "@biomejs/cli-win32-x64": "2.4.12" }, "bin": { "biome": "bin/biome" } }, "sha512-Rro7adQl3NLq/zJCIL98eElXKI8eEiBtoeu5TbXF/U3qbjuSc7Jb5rjUbeHHcquDWeSf3HnGP7XI5qGrlRk/pA=="],
- "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.4.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-jZ+Xc6qvD6tTH5jM6eKX44dcbyNqJHssfl2nnwT6vma6B1sj7ZLTGIk6N5QwVBs5xGN52r3trk5fgd3sQ9We9A=="],
+ "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.4.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-BnMU4Pc3ciEVteVpZ0BK33MLr7X57F5w1dwDLDn+/iy/yTrA4Q/N2yftidFtsA4vrDh0FMXDpacNV/Tl3fbmng=="],
- "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.4.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-Dh1a/+W+SUCXhEdL7TiX3ArPTFCQKJTI1mGncZNWfO+6suk+gYA4lNyJcBB+pwvF49uw0pEbUS49BgYOY4hzUg=="],
+ "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.4.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-x9uJ0bI1rJsWICp3VH8w/5PnAVD3A7SqzDpbrfoUQX1QyWrK5jSU4fRLo/wSgGeplCivbxBRKmt5Xq4/nWvq8A=="],
- "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.4.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-V/NFfbWhsUU6w+m5WYbBenlEAz8eYnSqRMDMAW3K+3v0tYVkNyZn8VU0XPxk/lOqNXLSCCrV7FmV/u3SjCBShg=="],
+ "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.4.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-tOwuCuZZtKi1jVzbk/5nXmIsziOB6yqN8c9r9QM0EJYPU6DpQWf11uBOSCfFKKM4H3d9ZoarvlgMfbcuD051Pw=="],
- "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.4.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-+sPAXq3bxmFwhVFJnSwkSF5Rw2ZAJMH3MF6C9IveAEOdSpgajPhoQhbbAK12SehN9j2QrHpk4J/cHsa/HqWaYQ=="],
+ "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.4.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-FhfpkAAlKL6kwvcVap0Hgp4AhZmtd3YImg0kK1jd7C/aSoh4SfsB2f++yG1rU0lr8Y5MCFJrcSkmssiL9Xnnig=="],
- "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.4.4", "", { "os": "linux", "cpu": "x64" }, "sha512-R4+ZCDtG9kHArasyBO+UBD6jr/FcFCTH8QkNTOCu0pRJzCWyWC4EtZa2AmUZB5h3e0jD7bRV2KvrENcf8rndBg=="],
+ "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.4.12", "", { "os": "linux", "cpu": "x64" }, "sha512-8pFeAnLU9QdW9jCIslB/v82bI0lhBmz2ZAKc8pVMFPO0t0wAHsoEkrUQUbMkIorTRIjbqyNZHA3lEXavsPWYSw=="],
- "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.4.4", "", { "os": "linux", "cpu": "x64" }, "sha512-gGvFTGpOIQDb5CQ2VC0n9Z2UEqlP46c4aNgHmAMytYieTGEcfqhfCFnhs6xjt0S3igE6q5GLuIXtdQt3Izok+g=="],
+ "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.4.12", "", { "os": "linux", "cpu": "x64" }, "sha512-dwTIgZrGutzhkQCuvHynCkyW6hJxUuyZqKKO0YNfaS2GUoRO+tOvxXZqZB6SkWAOdfZTzwaw8IEdUnIkHKHoew=="],
- "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.4.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-trzCqM7x+Gn832zZHgr28JoYagQNX4CZkUZhMUac2YxvvyDRLJDrb5m9IA7CaZLlX6lTQmADVfLEKP1et1Ma4Q=="],
+ "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.4.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-B0DLnx0vA9ya/3v7XyCaP+/lCpnbWbMOfUFFve+xb5OxyYvdHaS55YsSddr228Y+JAFk58agCuZTsqNiw2a6ig=="],
- "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.4", "", { "os": "win32", "cpu": "x64" }, "sha512-gnOHKVPFAAPrpoPt2t+Q6FZ7RPry/FDV3GcpU53P3PtLNnQjBmKyN2Vh/JtqXet+H4pme8CC76rScwdjDcT1/A=="],
+ "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.12", "", { "os": "win32", "cpu": "x64" }, "sha512-yMckRzTyZ83hkk8iDFWswqSdU8tvZxspJKnYNh7JZr/zhZNOlzH13k4ecboU6MurKExCe2HUkH75pGI/O2JwGA=="],
"@braintree/sanitize-url": ["@braintree/sanitize-url@6.0.2", "", {}, "sha512-Tbsj02wXCbqGmzdnXNk0SOF19ChhRU70BsroIi4Pm6Ehp56in6vch94mfbdQ17DozxkL3BAVjbZ4Qc1a0HFRAg=="],
@@ -854,25 +844,25 @@
"@tailwindcss/postcss": ["@tailwindcss/postcss@4.2.0", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.2.0", "@tailwindcss/oxide": "4.2.0", "postcss": "^8.5.6", "tailwindcss": "4.2.0" } }, "sha512-u6YBacGpOm/ixPfKqfgrJEjMfrYmPD7gEFRoygS/hnQaRtV0VCBdpkx5Ouw9pnaLRwwlgGCuJw8xLpaR0hOrQg=="],
- "@tanstack/devtools-event-client": ["@tanstack/devtools-event-client@0.4.0", "", {}, "sha512-RPfGuk2bDZgcu9bAJodvO2lnZeHuz4/71HjZ0bGb/SPg8+lyTA+RLSKQvo7fSmPSi8/vcH3aKQ8EM9ywf1olaw=="],
+ "@tootallnate/quickjs-emscripten": ["@tootallnate/quickjs-emscripten@0.23.0", "", {}, "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA=="],
- "@tanstack/form-core": ["@tanstack/form-core@1.28.3", "", { "dependencies": { "@tanstack/devtools-event-client": "^0.4.0", "@tanstack/pacer-lite": "^0.1.1", "@tanstack/store": "^0.8.1" } }, "sha512-DBhnu1d5VfACAYOAZJO8tsEUHjWczZMJY8v/YrtAJNWpwvL/3ogDuz8e6yUB2m/iVTNq6K8yrnVN2nrX0/BX/w=="],
+ "@ts-morph/common": ["@ts-morph/common@0.27.0", "", { "dependencies": { "fast-glob": "^3.3.3", "minimatch": "^10.0.1", "path-browserify": "^1.0.1" } }, "sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ=="],
- "@tanstack/pacer-lite": ["@tanstack/pacer-lite@0.1.1", "", {}, "sha512-y/xtNPNt/YeyoVxE/JCx+T7yjEzpezmbb+toK8DDD1P4m7Kzs5YR956+7OKexG3f8aXgC3rLZl7b1V+yNUSy5w=="],
+ "@tsconfig/svelte": ["@tsconfig/svelte@1.0.13", "", {}, "sha512-5lYJP45Xllo4yE/RUBccBT32eBlRDbqN8r1/MIvQbKxW3aFqaYPCNgm8D5V20X4ShHcwvYWNlKg3liDh1MlBoA=="],
- "@tanstack/react-form": ["@tanstack/react-form@1.28.3", "", { "dependencies": { "@tanstack/form-core": "1.28.3", "@tanstack/react-store": "^0.8.1" }, "peerDependencies": { "react": "^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-84yd0swZRcyC3Q46dYBH6bHf1tlIY1flchbdG3VwArg/wLVW5RdBenIrJhleHjk2OxXuF+9HoKQbHglJyWIXQA=="],
+ "@turbo/darwin-64": ["@turbo/darwin-64@2.9.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-X/56SnVXIQZBLKwniGTwEQTGmtE5brSACnKMBWpY3YafuxVYefrC2acamfjgxP7BG5w3I+6jf0UrLoSzgPcSJg=="],
- "@tanstack/react-store": ["@tanstack/react-store@0.8.1", "", { "dependencies": { "@tanstack/store": "0.8.1", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-XItJt+rG8c5Wn/2L/bnxys85rBpm0BfMbhb4zmPVLXAKY9POrp1xd6IbU4PKoOI+jSEGc3vntPRfLGSgXfE2Ig=="],
+ "@turbo/darwin-arm64": ["@turbo/darwin-arm64@2.9.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-aalBeSl4agT/QtYGDyf/XLajedWzUC9Vg/pm/YO6QQ93vkQ91Vz5uK1ta5RbVRDozQSz4njxUNqRNmOXDzW+qw=="],
- "@tanstack/store": ["@tanstack/store@0.8.1", "", {}, "sha512-PtOisLjUZPz5VyPRSCGjNOlwTvabdTBQ2K80DpVL1chGVr35WRxfeavAPdNq6pm/t7F8GhoR2qtmkkqtCEtHYw=="],
+ "@turbo/linux-64": ["@turbo/linux-64@2.9.6", "", { "os": "linux", "cpu": "x64" }, "sha512-YKi05jnNHaD7vevgYwahpzGwbsNNTwzU2c7VZdmdFm7+cGDP4oREUWSsainiMfRqjRuolQxBwRn8wf1jmu+YZA=="],
- "@tootallnate/quickjs-emscripten": ["@tootallnate/quickjs-emscripten@0.23.0", "", {}, "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA=="],
+ "@turbo/linux-arm64": ["@turbo/linux-arm64@2.9.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-02o/ZS69cOYEDczXvOB2xmyrtzjQ2hVFtWZK1iqxXUfzMmTjZK4UumrfNnjckSg+gqeBfnPRHa0NstA173Ik3g=="],
- "@ts-morph/common": ["@ts-morph/common@0.27.0", "", { "dependencies": { "fast-glob": "^3.3.3", "minimatch": "^10.0.1", "path-browserify": "^1.0.1" } }, "sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ=="],
+ "@turbo/windows-64": ["@turbo/windows-64@2.9.6", "", { "os": "win32", "cpu": "x64" }, "sha512-wVdQjvnBI15wB6JrA+43CtUtagjIMmX6XYO758oZHAsCNSxqRlJtdyujih0D8OCnwCRWiGWGI63zAxR0hO6s9g=="],
- "@tsconfig/svelte": ["@tsconfig/svelte@1.0.13", "", {}, "sha512-5lYJP45Xllo4yE/RUBccBT32eBlRDbqN8r1/MIvQbKxW3aFqaYPCNgm8D5V20X4ShHcwvYWNlKg3liDh1MlBoA=="],
+ "@turbo/windows-arm64": ["@turbo/windows-arm64@2.9.6", "", { "os": "win32", "cpu": "arm64" }, "sha512-1XUUyWW0W6FTSqGEhU8RHVqb2wP1SPkr7hIvBlMEwH9jr+sJQK5kqeosLJ/QaUv4ecSAd1ZhIrLoW7qslAzT4A=="],
- "@types/bun": ["@types/bun@1.3.9", "", { "dependencies": { "bun-types": "1.3.9" } }, "sha512-KQ571yULOdWJiMH+RIWIOZ7B2RXQGpL1YQrBtLIV3FqDcCu6FsbFUBwhdKUlCKUpS3PJDsHlJ1QKlpxoVR+xtw=="],
+ "@types/bun": ["@types/bun@1.3.12", "", { "dependencies": { "bun-types": "1.3.12" } }, "sha512-DBv81elK+/VSwXHDlnH3Qduw+KxkTIWi7TXkAeh24zpi5l0B2kUg9Ga3tb4nJaPcOFswflgi/yAvMVBPrxMB+A=="],
"@types/chai": ["@types/chai@5.2.3", "", { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA=="],
@@ -900,15 +890,13 @@
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
- "@types/jszip": ["@types/jszip@3.4.1", "", { "dependencies": { "jszip": "*" } }, "sha512-TezXjmf3lj+zQ651r6hPqvSScqBLvyPI9FxdXBqpEwBijNGQ2NXpaFW/7joGzveYkKQUil7iiDHLo6LV71Pc0A=="],
-
"@types/mdast": ["@types/mdast@3.0.15", "", { "dependencies": { "@types/unist": "^2" } }, "sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ=="],
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
"@types/mysql": ["@types/mysql@2.15.27", "", { "dependencies": { "@types/node": "*" } }, "sha512-YfWiV16IY0OeBfBCk8+hXKmdTKrKlwKN1MNKAPBu5JYxLwBEZl7QzeEpGnlZb3VMGJrrGmB84gXiH+ofs/TezA=="],
- "@types/node": ["@types/node@25.3.0", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A=="],
+ "@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
"@types/node-fetch": ["@types/node-fetch@2.6.13", "", { "dependencies": { "@types/node": "*", "form-data": "^4.0.4" } }, "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw=="],
@@ -1300,7 +1288,7 @@
"dompurify": ["dompurify@3.1.6", "", {}, "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ=="],
- "dotenv": ["dotenv@17.3.1", "", {}, "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA=="],
+ "dotenv": ["dotenv@17.4.2", "", {}, "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw=="],
"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=="],
@@ -2240,19 +2228,7 @@
"tunnel-rat": ["tunnel-rat@0.1.2", "", { "dependencies": { "zustand": "^4.3.2" } }, "sha512-lR5VHmkPhzdhrM092lI2nACsLO4QubF0/yoOhzX7c+wIpbN1GjHNzCc91QlpxBi+cnx8vVJ+Ur6vL5cEoQPFpQ=="],
- "turbo": ["turbo@2.8.10", "", { "optionalDependencies": { "turbo-darwin-64": "2.8.10", "turbo-darwin-arm64": "2.8.10", "turbo-linux-64": "2.8.10", "turbo-linux-arm64": "2.8.10", "turbo-windows-64": "2.8.10", "turbo-windows-arm64": "2.8.10" }, "bin": { "turbo": "bin/turbo" } }, "sha512-OxbzDES66+x7nnKGg2MwBA1ypVsZoDTLHpeaP4giyiHSixbsiTaMyeJqbEyvBdp5Cm28fc+8GG6RdQtic0ijwQ=="],
-
- "turbo-darwin-64": ["turbo-darwin-64@2.8.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-A03fXh+B7S8mL3PbdhTd+0UsaGrhfyPkODvzBDpKRY7bbeac4MDFpJ7I+Slf2oSkCEeSvHKR7Z4U71uKRUfX7g=="],
-
- "turbo-darwin-arm64": ["turbo-darwin-arm64@2.8.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-sidzowgWL3s5xCHLeqwC9M3s9M0i16W1nuQF3Mc7fPHpZ+YPohvcbVFBB2uoRRHYZg6yBnwD4gyUHKTeXfwtXA=="],
-
- "turbo-linux-64": ["turbo-linux-64@2.8.10", "", { "os": "linux", "cpu": "x64" }, "sha512-YK9vcpL3TVtqonB021XwgaQhY9hJJbKKUhLv16osxV0HkcQASQWUqR56yMge7puh6nxU67rQlTq1b7ksR1T3KA=="],
-
- "turbo-linux-arm64": ["turbo-linux-arm64@2.8.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-3+j2tL0sG95iBJTm+6J8/45JsETQABPqtFyYjVjBbi6eVGdtNTiBmHNKrbvXRlQ3ZbUG75bKLaSSDHSEEN+btQ=="],
-
- "turbo-windows-64": ["turbo-windows-64@2.8.10", "", { "os": "win32", "cpu": "x64" }, "sha512-hdeF5qmVY/NFgiucf8FW0CWJWtyT2QPm5mIsX0W1DXAVzqKVXGq+Zf+dg4EUngAFKjDzoBeN6ec2Fhajwfztkw=="],
-
- "turbo-windows-arm64": ["turbo-windows-arm64@2.8.10", "", { "os": "win32", "cpu": "arm64" }, "sha512-QGdr/Q8LWmj+ITMkSvfiz2glf0d7JG0oXVzGL3jxkGqiBI1zXFj20oqVY0qWi+112LO9SVrYdpHS0E/oGFrMbQ=="],
+ "turbo": ["turbo@2.9.6", "", { "optionalDependencies": { "@turbo/darwin-64": "2.9.6", "@turbo/darwin-arm64": "2.9.6", "@turbo/linux-64": "2.9.6", "@turbo/linux-arm64": "2.9.6", "@turbo/windows-64": "2.9.6", "@turbo/windows-arm64": "2.9.6" }, "bin": { "turbo": "bin/turbo" } }, "sha512-+v2QJey7ZUeUiuigkU+uFfklvNUyPI2VO2vBpMYJA+a1hKFLFiKtUYlRHdb3P9CrAvMzi0upbjI4WT+zKtqkBg=="],
"tw-animate-css": ["tw-animate-css@1.4.0", "", {}, "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ=="],
@@ -2270,7 +2246,7 @@
"uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="],
- "undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="],
+ "undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
"unicorn-magic": ["unicorn-magic@0.3.0", "", {}, "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA=="],
@@ -2438,6 +2414,8 @@
"@browserbasehq/stagehand/ai": ["ai@5.0.124", "", { "dependencies": { "@ai-sdk/gateway": "2.0.30", "@ai-sdk/provider": "2.0.1", "@ai-sdk/provider-utils": "3.0.20", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Li6Jw9F9qsvFJXZPBfxj38ddP2iURCnMs96f9Q3OeQzrDVcl1hvtwSEAuxA/qmfh6SDV2ERqFUOFzigvr0697g=="],
+ "@browserbasehq/stagehand/dotenv": ["dotenv@17.3.1", "", {}, "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA=="],
+
"@browserbasehq/stagehand/playwright": ["playwright@1.58.0", "", { "dependencies": { "playwright-core": "1.58.0" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-2SVA0sbPktiIY/MCOPX8e86ehA/e+tDNq+e5Y8qjKYti2Z/JG7xnronT/TXTIkKbYGWlCbuucZ6dziEgkoEjQQ=="],
"@browserbasehq/stagehand/playwright-core": ["playwright-core@1.58.0", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-aaoB1RWrdNi3//rOeKuMiS65UCcgOVljU46At6eFcOFPFHWtd2weHRRow6z/n+Lec0Lvu0k9ZPKJSjPugikirw=="],
@@ -2560,6 +2538,8 @@
"@ts-morph/common/minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="],
+ "@types/bun/bun-types": ["bun-types@1.3.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-HqOLj5PoFajAQciOMRiIZGNoKxDJSr6qigAttOX40vJuSp6DN/CxWp9s3C1Xwm4oH7ybueITwiaOcWXoYVoRkA=="],
+
"@types/connect/@types/node": ["@types/node@24.10.9", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw=="],
"@types/mysql/@types/node": ["@types/node@24.10.9", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw=="],
diff --git a/package.json b/package.json
index 43200dc..ec625e8 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,7 @@
"tests/*"
],
"catalog": {
- "dotenv": "^17.2.4",
+ "dotenv": "^17.4.2",
"zod": "^4.1.13",
"typescript": "^5",
"convex": "^1.31.7"
@@ -25,17 +25,12 @@
"dev:setup": "turbo -F @sketchi/backend dev:setup",
"seed:palantir-icons": "bun --cwd packages/backend run seed:palantir-icons"
},
- "dependencies": {
- "@sketchi/env": "workspace:*",
- "dotenv": "^17.3.1",
- "zod": "^4.3.6"
- },
"devDependencies": {
- "@biomejs/biome": "2.4.4",
+ "@biomejs/biome": "2.4.12",
"@sketchi/config": "workspace:*",
- "@types/bun": "^1.3.9",
- "@types/node": "^25.3.0",
- "turbo": "^2.8.10",
+ "@types/bun": "^1.3.12",
+ "@types/node": "^25.6.0",
+ "turbo": "^2.9.6",
"typescript": "^5.9.3",
"ultracite": "7.2.3"
},
diff --git a/packages/backend/convex/lib/excalidrawShareLinks.ts b/packages/backend/convex/lib/excalidrawShareLinks.ts
index e9cf411..fd37b72 100644
--- a/packages/backend/convex/lib/excalidrawShareLinks.ts
+++ b/packages/backend/convex/lib/excalidrawShareLinks.ts
@@ -629,7 +629,7 @@ async function fetchLinkSharing(sceneId: string): Promise {
fields?: { linkSharing?: { integerValue?: string } };
};
const raw = json.fields?.linkSharing?.integerValue;
- const value = raw != null ? Number(raw) : Number.NaN;
+ const value = raw == null ? Number.NaN : Number(raw);
return Number.isFinite(value) ? value : undefined;
} catch {
return undefined;
diff --git a/packages/backend/lib/agents/diagram-generator.ts b/packages/backend/lib/agents/diagram-generator.ts
deleted file mode 100644
index 5b60534..0000000
--- a/packages/backend/lib/agents/diagram-generator.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-import { generateObjectWithRetry, getModel } from "../ai-utils";
-import type { IntermediateFormat } from "../diagram-intermediate";
-import { convertIntermediateToDiagram } from "../diagram-layout";
-import { type Diagram, DiagramSchema } from "../diagram-structure";
-import { CHART_VISUAL_SPECS } from "../prompts/chart-specs";
-
-const DEFAULT_CHART_PROMPT = `Generate a diagram:
-- Use rectangles for main components
-- Use ellipses for external entities or start/end points
-- Use diamonds for decision points
-- Connect related elements with arrows
-- Apply colors to group related items`;
-
-function getChartPrompt(chartType: string): string {
- return CHART_VISUAL_SPECS[chartType]?.trim() ?? DEFAULT_CHART_PROMPT;
-}
-
-export interface DiagramGeneratorOptions {
- maxRetries?: number;
- timeoutMs?: number;
-}
-
-export interface DiagramGeneratorResult {
- diagram: Diagram;
- durationMs: number;
- tokens?: number;
-}
-
-export async function generateDiagram(
- intermediate: IntermediateFormat,
- options: DiagramGeneratorOptions = {}
-): Promise {
- const { timeoutMs = 60_000, maxRetries = 2 } = options;
- const start = Date.now();
-
- const chartType = intermediate.graphOptions?.diagramType ?? "flowchart";
- const chartPrompt = getChartPrompt(chartType);
-
- const systemPrompt = `You are a diagram element generator. Convert the provided components and relationships into precise diagram elements.
-
-${chartPrompt}
-
-Rules:
-- Every shape needs a unique id
-- Arrow fromId/toId must reference valid shape ids
-- Preserve all component labels exactly
-- Apply colors from the input if provided
-- Use appropriate shapes based on component context`;
-
- const userPrompt = `Convert this to diagram elements:
-
-Chart Type: ${chartType}
-Layout: ${intermediate.graphOptions?.layout?.direction || "TB"}
-
-Components:
-${intermediate.nodes.map((n) => `- ${n.id}: "${n.label}" (kind: ${n.kind || "default"})`).join("\n")}
-
-Relationships:
-${intermediate.edges.map((r) => `- ${r.fromId} -> ${r.toId}${r.label ? ` [${r.label}]` : ""}`).join("\n")}`;
-
- const result = await generateObjectWithRetry({
- model: getModel(),
- schema: DiagramSchema,
- system: systemPrompt,
- prompt: userPrompt,
- timeoutMs,
- maxRetries,
- });
-
- return {
- diagram: result.object as Diagram,
- tokens: result.usage?.totalTokens,
- durationMs: Date.now() - start,
- };
-}
-
-export function generateDiagramDirect(
- intermediate: IntermediateFormat
-): Diagram {
- return convertIntermediateToDiagram(intermediate);
-}
diff --git a/packages/backend/lib/json-repair.ts b/packages/backend/lib/json-repair.ts
deleted file mode 100644
index 742d91f..0000000
--- a/packages/backend/lib/json-repair.ts
+++ /dev/null
@@ -1,108 +0,0 @@
-const MARKDOWN_JSON_FENCE_START = /^```(?:json|javascript|js)?\s*\n?/i;
-const MARKDOWN_FENCE_END = /\n?```\s*$/;
-const JSON_START_PATTERN = /[[{]/;
-const TRAILING_COMMA = /,\s*$/;
-
-function stripMarkdownFences(input: string): string {
- return input
- .trim()
- .replace(MARKDOWN_JSON_FENCE_START, "")
- .replace(MARKDOWN_FENCE_END, "")
- .trim();
-}
-
-function findJsonStart(text: string): number {
- return text.search(JSON_START_PATTERN);
-}
-
-interface ParseState {
- inString: boolean;
- isEscaped: boolean;
- stack: string[];
-}
-
-function processCharacter(
- ch: string,
- state: ParseState
-): { complete: boolean } {
- if (state.inString) {
- if (state.isEscaped) {
- state.isEscaped = false;
- return { complete: false };
- }
- if (ch === "\\") {
- state.isEscaped = true;
- return { complete: false };
- }
- if (ch === '"') {
- state.inString = false;
- }
- return { complete: false };
- }
-
- if (ch === '"') {
- state.inString = true;
- return { complete: false };
- }
-
- if (ch === "{") {
- state.stack.push("}");
- return { complete: false };
- }
-
- if (ch === "[") {
- state.stack.push("]");
- return { complete: false };
- }
-
- if (ch === "}" || ch === "]") {
- if (state.stack.length && state.stack.at(-1) === ch) {
- state.stack.pop();
- }
- if (state.stack.length === 0) {
- return { complete: true };
- }
- }
-
- return { complete: false };
-}
-
-function closeUnclosedBrackets(text: string, state: ParseState): string {
- let result = text;
- if (state.inString) {
- result += '"';
- }
- result = result.replace(TRAILING_COMMA, "");
- while (state.stack.length) {
- result += state.stack.pop();
- }
- return result;
-}
-
-export function repairJsonClosure(input: string): string {
- const processed = stripMarkdownFences(input);
- const start = findJsonStart(processed);
-
- if (start === -1) {
- return processed;
- }
-
- const state: ParseState = {
- inString: false,
- isEscaped: false,
- stack: [],
- };
-
- for (let i = start; i < processed.length; i++) {
- const char = processed[i];
- if (char === undefined) {
- continue;
- }
- const result = processCharacter(char, state);
- if (result.complete) {
- return processed.slice(start, i + 1);
- }
- }
-
- return closeUnclosedBrackets(processed.slice(start), state);
-}
diff --git a/packages/backend/lib/output.ts b/packages/backend/lib/output.ts
deleted file mode 100644
index f401943..0000000
--- a/packages/backend/lib/output.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import { mkdir, writeFile } from "node:fs/promises";
-import { join } from "node:path";
-
-const OUTPUT_DIR = join(import.meta.dirname, "../output");
-
-function getTimestamp(): string {
- const now = new Date();
- const year = now.getFullYear();
- const month = String(now.getMonth() + 1).padStart(2, "0");
- const day = String(now.getDate()).padStart(2, "0");
- const hours = String(now.getHours()).padStart(2, "0");
- const minutes = String(now.getMinutes()).padStart(2, "0");
- const seconds = String(now.getSeconds()).padStart(2, "0");
- return `${year}-${month}-${day}_${hours}-${minutes}-${seconds}`;
-}
-
-export interface OutputSession {
- dir: string;
- saveJson: (name: string, data: unknown) => Promise;
- savePng: (name: string, buffer: Buffer) => Promise;
- saveText: (name: string, content: string) => Promise;
- timestamp: string;
-}
-
-export async function createOutputSession(
- prefix = "run"
-): Promise {
- const timestamp = getTimestamp();
- const dir = join(OUTPUT_DIR, `${prefix}_${timestamp}`);
- await mkdir(dir, { recursive: true });
-
- const saveJson = async (name: string, data: unknown): Promise => {
- const path = join(dir, `${name}.json`);
- await writeFile(path, JSON.stringify(data, null, 2));
- return path;
- };
-
- const savePng = async (name: string, buffer: Buffer): Promise => {
- const path = join(dir, `${name}.png`);
- await writeFile(path, buffer);
- return path;
- };
-
- const saveText = async (name: string, content: string): Promise => {
- const path = join(dir, `${name}.txt`);
- await writeFile(path, content);
- return path;
- };
-
- return { dir, timestamp, saveJson, savePng, saveText };
-}
diff --git a/packages/backend/package.json b/packages/backend/package.json
index 97fcd0b..9707cb3 100644
--- a/packages/backend/package.json
+++ b/packages/backend/package.json
@@ -34,7 +34,7 @@
"devDependencies": {
"@edge-runtime/vm": "^5.0.0",
"@sketchi/config": "workspace:*",
- "@types/node": "^25.3.0",
+ "@types/node": "^25.6.0",
"@types/pako": "^2.0.4",
"convex-test": "^0.0.41",
"typescript": "catalog:",
diff --git a/packages/env/package.json b/packages/env/package.json
index 6a4cb39..e87c21b 100644
--- a/packages/env/package.json
+++ b/packages/env/package.json
@@ -8,7 +8,6 @@
},
"dependencies": {
"@t3-oss/env-nextjs": "^0.13.10",
- "dotenv": "catalog:",
"zod": "catalog:"
},
"devDependencies": {
diff --git a/packages/opencode-excalidraw/package.json b/packages/opencode-excalidraw/package.json
index 47624fa..3e0566e 100644
--- a/packages/opencode-excalidraw/package.json
+++ b/packages/opencode-excalidraw/package.json
@@ -38,7 +38,7 @@
},
"devDependencies": {
"@opencode-ai/plugin": "1.2.10",
- "@types/node": "^25.3.0",
+ "@types/node": "^25.6.0",
"bun-types": "1.3.9",
"typescript": "^5.9.3"
},
diff --git a/packages/shared/src/excalidraw-share-links.ts b/packages/shared/src/excalidraw-share-links.ts
index 2cad354..0879784 100644
--- a/packages/shared/src/excalidraw-share-links.ts
+++ b/packages/shared/src/excalidraw-share-links.ts
@@ -567,7 +567,7 @@ async function fetchLinkSharing(sceneId: string): Promise {
fields?: { linkSharing?: { integerValue?: string } };
};
const raw = json.fields?.linkSharing?.integerValue;
- const value = raw != null ? Number(raw) : Number.NaN;
+ const value = raw == null ? Number.NaN : Number(raw);
return Number.isFinite(value) ? value : undefined;
} catch {
return undefined;
diff --git a/tests/api/plan/parse-v2-share-link.ts b/tests/api/plan/parse-v2-share-link.ts
deleted file mode 100644
index 2a3a3a8..0000000
--- a/tests/api/plan/parse-v2-share-link.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-// Scenario: Parse V2 Excalidraw share link via public API.
-// - Call /api/diagrams/parse with a known V2 share URL.
-// - Assert status 200 and expected counts for nodes/elements/edges.
diff --git a/tests/e2e/package.json b/tests/e2e/package.json
index 7460203..9aba34d 100644
--- a/tests/e2e/package.json
+++ b/tests/e2e/package.json
@@ -11,18 +11,18 @@
"excalidraw-plus-links": "bun run src/scenarios/unauthenticated/excalidraw-plus-links.ts",
"diagram-studio-happy-path": "bun run src/scenarios/unauthenticated/diagram-studio-happy-path.ts",
"diagram-studio-occ-conflict": "bun run src/scenarios/unauthenticated/diagram-studio-occ-conflict.ts",
- "opencode-web-continuity": "bun run src/scenarios/unauthenticated/opencode-web-continuity.ts"
+ "opencode-web-continuity": "bun run src/scenarios/unauthenticated/opencode-web-continuity.ts",
+ "run-scenarios": "bun run scripts/run-scenarios.ts"
},
"dependencies": {
"@browserbasehq/stagehand": "^3.0.8",
"@sketchi/shared": "workspace:*",
- "convex": "^1.32.0",
- "dotenv": "^17.3.1",
- "pako": "^2.1.0"
+ "dotenv": "catalog:"
},
"devDependencies": {
"@playwright/test": "^1.58.2",
- "@types/bun": "latest",
+ "@types/bun": "^1.3.12",
+ "bun-types": "1.3.9",
"rrweb-player": "1.0.0-alpha.4"
}
}
diff --git a/tests/e2e/src/scenarios/unauthenticated/diagram-studio-occ-conflict.ts b/tests/e2e/src/scenarios/unauthenticated/diagram-studio-occ-conflict.ts
index cb0fcf5..c3df2ef 100644
--- a/tests/e2e/src/scenarios/unauthenticated/diagram-studio-occ-conflict.ts
+++ b/tests/e2e/src/scenarios/unauthenticated/diagram-studio-occ-conflict.ts
@@ -272,18 +272,18 @@ async function main() {
await sleep(1200);
await addCanvasElement(pageB);
- if (versionAValue !== null) {
+ if (versionAValue === null) {
+ const savedA2 = await waitForSaveStatus(pageA, "Saved", 35_000);
+ if (!savedA2) {
+ throw new Error("Tab A second save did not complete.");
+ }
+ } else {
const advanced = await waitForVersionAtLeast(pageA, versionAValue + 1);
if (!advanced) {
throw new Error(
`Tab A version did not advance to >= v${versionAValue + 1}.`
);
}
- } else {
- const savedA2 = await waitForSaveStatus(pageA, "Saved", 35_000);
- if (!savedA2) {
- throw new Error("Tab A second save did not complete.");
- }
}
const versionA2 = await getTestIdText(pageA, "diagram-session-version");
console.log(` Tab A new version: ${versionA2}`);
diff --git a/tests/e2e/src/scenarios/unauthenticated/icon-library-generator-invalid-svg.ts b/tests/e2e/src/scenarios/unauthenticated/icon-library-generator-invalid-svg.ts
deleted file mode 100644
index 290e20f..0000000
--- a/tests/e2e/src/scenarios/unauthenticated/icon-library-generator-invalid-svg.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
-Scenario: Icon library generator invalid SVG handling
-
-Intent: Ensure invalid SVG uploads are rejected without breaking the editor.
-
-Steps:
-- Visit Icon Library Generator.
-- Create a new library.
-- Attempt to upload an invalid SVG (malformed or non-SVG file renamed .svg).
-
-Success:
-- UI shows a clear error toast.
-- No icons are added to the grid.
-- Editor remains usable (upload valid SVG afterward works).
-*/
diff --git a/tests/e2e/src/scenarios/unauthenticated/mcp-v2-share-link.ts b/tests/e2e/src/scenarios/unauthenticated/mcp-v2-share-link.ts
index d36db46..e1f00fa 100644
--- a/tests/e2e/src/scenarios/unauthenticated/mcp-v2-share-link.ts
+++ b/tests/e2e/src/scenarios/unauthenticated/mcp-v2-share-link.ts
@@ -24,8 +24,8 @@ Success:
import { mkdir, readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
+import { chromium } from "@playwright/test";
import { parseExcalidrawShareLink } from "@sketchi/shared";
-import { chromium } from "playwright";
const FIXTURE_PATH = join(
import.meta.dir,