diff --git a/.cargo/config.toml b/.cargo/config.toml index 8624e47b..a0050cd3 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -15,35 +15,35 @@ [target.x86_64-apple-darwin] rustflags = [ "-C", "link-arg=-fuse-ld=/usr/bin/ld", - "-C", "codegen-units=16", - "-Z", "threads=16", # Parallel frontend (type check, borrow check, MIR opt) + "-C", "codegen-units=20", + "-Z", "threads=20", # Parallel frontend (type check, borrow check, MIR opt) ] [target.aarch64-apple-darwin] rustflags = [ "-C", "link-arg=-fuse-ld=/usr/bin/ld", - "-C", "codegen-units=16", - "-Z", "threads=16", # Parallel frontend (type check, borrow check, MIR opt) + "-C", "codegen-units=20", + "-Z", "threads=20", # Parallel frontend (type check, borrow check, MIR opt) ] [target.x86_64-unknown-linux-gnu] rustflags = [ "-C", "link-arg=-fuse-ld=lld", - "-C", "codegen-units=16", - "-Z", "threads=16", + "-C", "codegen-units=20", + "-Z", "threads=20", ] [target.x86_64-pc-windows-msvc] rustflags = [ "-C", "link-arg=/DEBUG:NONE", - "-C", "codegen-units=16", - "-Z", "threads=16", + "-C", "codegen-units=20", + "-Z", "threads=20", ] # Build configuration [build] # Parallel compilation jobs (defaults to number of CPU cores) -jobs = 16 +jobs = 20 # Incremental compilation for faster rebuilds (enabled by default in dev) incremental = true diff --git a/.tool-versions b/.tool-versions index 6dbd06ac..3a0bda29 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ nodejs 24.3.0 -rust nightly +rust nightly \ No newline at end of file diff --git a/README.md b/README.md index 496bd2cf..0b734eab 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,7 @@ -# Treq - Coding Agent Orchestrator +# Treq - Coding Agent Orchestrator - test remote clone Treq transforms AI-generated code into local isolated pull requests. -> **πŸš€ One-Shot at Speed πŸš€** -> -> _Ship quality code to production without the AI slop_ - ---- - ## What is Treq? AI agents can create results fast, but they don’t organize anything. Their outputs stack on top of each other, overwrite previous work, and make it hard to see what changed or what should happen next. @@ -18,12 +12,26 @@ It gives each agent result its own space, shows it clearly to the developer for Now, instead of a messy pile of AI output, you get a clean, organized workflow you can control. -## Key Features +## Features + +### Code Reviews + +Inspect and iterate on each change for a human-in-the-loop agentic workflow. + + + +- Review the code diffs just like a familiar Github PR, annotate and comment on code, and then send it to an agent for changes. +- Spotted an issue when browsing files? Send it to an agent for adjustments in the background. + +### Isolated Workspaces + +Coding agents work in isolated copies of the codebase, ensuring changes are independent from each other while keeping your current repository clean for planning. + + -- **🌳 Agent Isolation**: Coding agents work in isolation on dedicated Git worktrees, paralleized and isolated. -- **πŸ’» Integrated Terminal**: Use Claude Code in full inteactive mode, with seamless integeration with planning modes and Git worktree management -- **πŸ” Code Review**: Inspect and iterate on each change for a human-in-the-loop agentic workflow. +- Workspaces are isolated but interlinked - move changes around workspaces, or split and stack workspaces as needed. +- Got a code conflict? No problem! Let the agent handle it the grunt work. ## License -Licensed under the Apache License, Version 2.0 \ No newline at end of file +Licensed under the Apache License, Version 2.0 diff --git a/agents.md b/agents.md index ef0a00e7..7f42c8ff 100644 --- a/agents.md +++ b/agents.md @@ -37,7 +37,7 @@ npm run tauri dev # Run in dev mode (Rust + frontend dev server) **Core Components:** - **App.tsx** - Root with QueryClient provider, routing, and global state - **components/Dashboard.tsx** - Main UI controller (repository dashboard) -- **components/SessionTerminal.tsx** - PTY terminal with ghostty-web integration +- **components/ShowWorkspace.tsx** - Workspace viewer with overview, changes, and files tabs - **components/StagingDiffViewer.tsx** - Git staging area with file tree and diff view - **components/AnnotatableDiffViewer.tsx** - Diff viewer with annotation support - **components/ui/** - Shadcn-based UI primitives diff --git a/docs/src/components/HomepageFeatures/index.tsx b/docs/src/components/HomepageFeatures/index.tsx index c2551fb9..f2c86b7a 100644 --- a/docs/src/components/HomepageFeatures/index.tsx +++ b/docs/src/components/HomepageFeatures/index.tsx @@ -2,6 +2,9 @@ import type {ReactNode} from 'react'; import clsx from 'clsx'; import Heading from '@theme/Heading'; import styles from './styles.module.css'; +import MountainSvg from '@site/static/img/undraw_docusaurus_mountain.svg'; +import TreeSvg from '@site/static/img/undraw_docusaurus_tree.svg'; +import ReactSvg from '@site/static/img/undraw_docusaurus_react.svg'; type FeatureItem = { title: string; @@ -12,7 +15,7 @@ type FeatureItem = { const FeatureList: FeatureItem[] = [ { title: 'Easy to Use', - Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default, + Svg: MountainSvg, description: ( <> Docusaurus was designed from the ground up to be easily installed and @@ -22,7 +25,7 @@ const FeatureList: FeatureItem[] = [ }, { title: 'Focus on What Matters', - Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default, + Svg: TreeSvg, description: ( <> Docusaurus lets you focus on your docs, and we'll do the chores. Go @@ -32,7 +35,7 @@ const FeatureList: FeatureItem[] = [ }, { title: 'Powered by React', - Svg: require('@site/static/img/undraw_docusaurus_react.svg').default, + Svg: ReactSvg, description: ( <> Extend or customize your website layout by reusing React. Docusaurus can diff --git a/docs/src/pages/index.tsx b/docs/src/pages/index.tsx index 6be40e1c..7157ee8c 100644 --- a/docs/src/pages/index.tsx +++ b/docs/src/pages/index.tsx @@ -8,7 +8,6 @@ import Heading from '@theme/Heading'; import styles from './index.module.css'; function HomepageHeader() { - const {siteConfig} = useDocusaurusContext(); return (
@@ -162,9 +161,9 @@ function ProblemSection(): ReactNode {

-
- Today's AI development workflow is basically: -
+
+ Today’s AI development workflow is basically: +
copy/paste patches into editors
@@ -180,7 +179,7 @@ function ProblemSection(): ReactNode {

- It's chaos disguised as productivity. + It’s chaos disguised as productivity.

@@ -265,9 +264,9 @@ function FeaturesSection(): ReactNode {
Claude Code–ready terminal per branch
-
- Iterate patches safely until they're right -
+
+ Iterate patches safely until they’re right +
Merge only when approved
diff --git a/eslint-rules/no-banned-tailwind-classes.js b/eslint-rules/no-banned-tailwind-classes.js new file mode 100644 index 00000000..6017823e --- /dev/null +++ b/eslint-rules/no-banned-tailwind-classes.js @@ -0,0 +1,152 @@ +/** + * ESLint rule to ban specific Tailwind CSS classes + * + * @example + * // In eslint.config.js: + * rules: { + * "local/no-banned-tailwind-classes": ["error", { + * bannedClasses: ["text-xs", "text-2xs"] + * }] + * } + */ + +module.exports = { + meta: { + type: "problem", + docs: { + description: "Disallow specific Tailwind CSS classes", + category: "Stylistic Issues", + recommended: false, + }, + schema: [ + { + type: "object", + properties: { + bannedClasses: { + type: "array", + items: { type: "string" }, + uniqueItems: true, + }, + }, + additionalProperties: false, + }, + ], + messages: { + bannedClass: 'Tailwind class "{{className}}" is banned. Consider using a different size class.', + }, + }, + + create(context) { + const options = context.options[0] || {}; + const bannedClasses = new Set(options.bannedClasses || []); + + if (bannedClasses.size === 0) { + // No banned classes configured, skip processing + return {}; + } + + /** + * Extract class names from a string + */ + function extractClassNames(str) { + return str.split(/\s+/).filter(Boolean); + } + + /** + * Check if any class in the string is banned and report + */ + function checkClasses(node, classString) { + const classes = extractClassNames(classString); + for (const className of classes) { + if (bannedClasses.has(className)) { + context.report({ + node, + messageId: "bannedClass", + data: { className }, + }); + } + } + } + + /** + * Recursively extract class strings from various node types + */ + function extractFromNode(node) { + if (!node) return; + + // String literal: "text-xs" + if (node.type === "Literal" && typeof node.value === "string") { + checkClasses(node, node.value); + } + + // Template literal: `text-xs ${var}` + else if (node.type === "TemplateLiteral") { + for (const quasi of node.quasis) { + checkClasses(quasi, quasi.value.raw); + } + } + + // JSX expression: className={"text-xs"} + else if (node.type === "JSXExpressionContainer") { + extractFromNode(node.expression); + } + + // Call expression: cn("text-xs", ...) or clsx("text-xs", ...) + else if (node.type === "CallExpression") { + const calleeName = + node.callee.type === "Identifier" ? node.callee.name : null; + + // Only process cn() and clsx() calls + if (calleeName === "cn" || calleeName === "clsx") { + for (const arg of node.arguments) { + extractFromNode(arg); + } + } + } + + // Ternary expression: condition ? "text-xs" : "text-sm" + else if (node.type === "ConditionalExpression") { + extractFromNode(node.consequent); + extractFromNode(node.alternate); + } + + // Logical expression: condition && "text-xs" + else if (node.type === "LogicalExpression") { + extractFromNode(node.left); + extractFromNode(node.right); + } + + // Array expression: ["text-xs", condition && "other"] + else if (node.type === "ArrayExpression") { + for (const element of node.elements) { + if (element) { + extractFromNode(element); + } + } + } + + // Object expression (for conditional classes): { "text-xs": true } + else if (node.type === "ObjectExpression") { + for (const prop of node.properties) { + if (prop.type === "Property" && prop.key.type === "Literal") { + const keyValue = prop.key.value; + if (typeof keyValue === "string") { + checkClasses(prop.key, keyValue); + } + } + } + } + } + + return { + JSXAttribute(node) { + // Only check className attributes + if (node.name.name !== "className") { + return; + } + + extractFromNode(node.value); + }, + }; + }, +}; diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 00000000..63403988 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,76 @@ +import js from "@eslint/js"; +import globals from "globals"; +import tseslint from "typescript-eslint"; +import pluginReact from "eslint-plugin-react"; +import { defineConfig } from "eslint/config"; + +const ignoredGlobs = [ + "docs/.docusaurus/**", + "docs/build/**", + ".treq/**", + "src-tauri/target/**", + "dist/**", + "node_modules/**", +]; + +export default defineConfig([ + { + ignores: ignoredGlobs, + }, + { + files: ["**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"], + ignores: ignoredGlobs, + plugins: { js }, + extends: ["js/recommended"], + languageOptions: { globals: globals.browser }, + }, + { + extends: [tseslint.configs.recommended], + }, + pluginReact.configs.flat.recommended, + { + settings: { + react: { version: "detect" }, + }, + }, + { + rules: { + // TypeScript handles prop types validation + "react/prop-types": "off", + // Not needed with modern React JSX transform + "react/react-in-jsx-scope": "off", + // Allow display name to be inferred + "react/display-name": "off", + // Allow unused vars prefixed with _ + "@typescript-eslint/no-unused-vars": [ + "error", + { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + caughtErrorsIgnorePattern: "^_", + }, + ], + }, + }, + { + // Relaxed rules for config files + files: ["*.config.{js,ts}", "tailwind.config.js"], + languageOptions: { + globals: { + ...globals.node, + require: "readonly", + }, + }, + rules: { + "@typescript-eslint/no-require-imports": "off", + "no-undef": "off", + }, + }, + { + // Relaxed rules for test files + files: ["test/**/*.{ts,tsx}"], + rules: { + "@typescript-eslint/no-explicit-any": "off", + }, + }, +]); diff --git a/package-lock.json b/package-lock.json index 670f592e..e92c198f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,31 +27,61 @@ "class-variance-authority": "^0.7.0", "clsx": "^2.0.0", "cmdk": "^1.1.1", - "ghostty-web": "^0.3.0", "lucide-react": "^0.294.0", "monaco-editor": "^0.45.0", + "prism-themes": "^1.9.0", "prismjs": "^1.30.0", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-markdown": "^10.1.0", "react-window": "^2.2.3", + "remark-gfm": "^4.0.1", "tailwind-merge": "^2.1.0", "uuid": "^13.0.0" }, "devDependencies": { + "@eslint/css": "^0.14.1", + "@eslint/js": "^9.39.2", + "@eslint/markdown": "^7.5.1", + "@tailwindcss/typography": "^0.5.19", "@tauri-apps/cli": "^2", + "@testing-library/dom": "^10.4.1", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.1", "@types/node": "^20.10.5", "@types/prismjs": "^1.26.5", - "@types/react": "^18.3.1", - "@types/react-dom": "^18.3.1", + "@types/react": "^18.3.27", + "@types/react-dom": "^18.3.7", "@vitejs/plugin-react": "^4.3.4", "autoprefixer": "^10.4.16", + "eslint": "^9.39.2", + "eslint-plugin-react": "^7.37.5", + "globals": "^16.5.0", + "jsdom": "^27.3.0", + "oxlint": "^1.33.0", "postcss": "^8.4.32", "tailwindcss": "^3.3.6", "typescript": "~5.6.2", + "typescript-eslint": "^8.50.0", "vite": "^6.0.3", - "vite-plugin-monaco-editor": "^1.1.0" + "vite-plugin-monaco-editor": "^1.1.0", + "vitest": "^4.0.15" } }, + "node_modules/@acemir/cssom": { + "version": "0.9.29", + "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.29.tgz", + "integrity": "sha512-G90x0VW+9nW4dFajtjCoT+NM0scAfH9Mb08IcjgFHYbfiL/lU04dTF9JuVOi3/OH+DJCQdcIseSXkdCB9Ky6JA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@adobe/css-tools": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz", + "integrity": "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==", + "dev": true, + "license": "MIT" + }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", @@ -65,6 +95,61 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@asamuzakjp/css-color": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.0.tgz", + "integrity": "sha512-9xiBAtLn4aNsa4mDnpovJvBn72tNEIACyvlqaNJ+ADemR+yeMJWnBudOi2qGDviJa7SwcDOU/TRh5dnET7qk0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.4", + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "lru-cache": "^11.2.2" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { + "version": "11.2.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", + "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@asamuzakjp/dom-selector": { + "version": "6.7.6", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.7.6.tgz", + "integrity": "sha512-hBaJER6A9MpdG3WgdlOolHmbOYvSk46y7IQN/1+iqiCuUu6iWdQrs9DGKF8ocqsEqWujWf/V7b7vaDgiUmIvUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/nwsapi": "^2.3.9", + "bidi-js": "^1.0.3", + "css-tree": "^3.1.0", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.2.4" + } + }, + "node_modules/@asamuzakjp/dom-selector/node_modules/lru-cache": { + "version": "11.2.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", + "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@asamuzakjp/nwsapi": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", + "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@babel/code-frame": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", @@ -299,6 +384,16 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/runtime": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", @@ -347,6 +442,144 @@ "node": ">=6.9.0" } }, + "node_modules/@csstools/color-helpers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.1.0", + "@csstools/css-calc": "^2.1.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.14.tgz", + "integrity": "sha512-zSlIxa20WvMojjpCSy8WrNpcZ61RqfTfX3XTaOeVlGJrt/8HF3YbzgFZa01yTbT4GWQLwfTcC3EB8i3XnB647Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.12", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", @@ -789,147 +1022,391 @@ "node": ">=18" } }, - "node_modules/@floating-ui/core": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", - "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "dev": true, "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.2.10" + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@floating-ui/dom": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", - "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", - "license": "MIT", - "dependencies": { - "@floating-ui/core": "^1.7.3", - "@floating-ui/utils": "^0.2.10" + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@floating-ui/react-dom": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz", - "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==", + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "@floating-ui/dom": "^1.7.4" + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@floating-ui/utils": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", - "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", - "license": "MIT" - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", "dev": true, - "license": "ISC", + "license": "Apache-2.0", "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + "@eslint/core": "^0.17.0" }, "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "node_modules/@eslint/css": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@eslint/css/-/css-0.14.1.tgz", + "integrity": "sha512-NXiteSacmpaXqgyIW3+GcNzexXyfC0kd+gig6WTjD4A74kBGJeNx1tV0Hxa0v7x0+mnIyKfGPhGNs1uhRFdh+w==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" + "@eslint/core": "^0.17.0", + "@eslint/css-tree": "^3.6.6", + "@eslint/plugin-kit": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "node_modules/@eslint/css-tree": { + "version": "3.6.8", + "resolved": "https://registry.npmjs.org/@eslint/css-tree/-/css-tree-3.6.8.tgz", + "integrity": "sha512-s0f40zY7dlMp8i0Jf0u6l/aSswS0WRAgkhgETgiCJRcxIWb4S/Sp9uScKHWbkM3BnoFLbJbmOYk5AZUDFVxaLA==", "dev": true, "license": "MIT", + "dependencies": { + "mdn-data": "2.23.0", + "source-map-js": "^1.0.1" + }, "engines": { - "node": ">=6.0.0" + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "node_modules/@eslint/eslintrc": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@monaco-editor/loader": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.6.1.tgz", - "integrity": "sha512-w3tEnj9HYEC73wtjdpR089AqkUPskFRcdkxsiSFt3SoUc3OHpmu+leP94CXBm4mHfefmhsdfI0ZQu6qJ0wgtPg==", + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, "license": "MIT", - "dependencies": { - "state-local": "^1.0.6" + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@monaco-editor/react": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.7.0.tgz", - "integrity": "sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==", + "node_modules/@eslint/js": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", + "dev": true, "license": "MIT", - "dependencies": { - "@monaco-editor/loader": "^1.5.0" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependencies": { - "monaco-editor": ">= 0.25.0 < 1", - "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" + "funding": { + "url": "https://eslint.org/donate" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@eslint/markdown": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/@eslint/markdown/-/markdown-7.5.1.tgz", + "integrity": "sha512-R8uZemG9dKTbru/DQRPblbJyXpObwKzo8rv1KYGGuPUPtjM4LXBYM9q5CIZAComzZupws3tWbDwam5AFpPLyJQ==", "dev": true, "license": "MIT", + "workspaces": [ + "examples/*" + ], "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "@eslint/core": "^0.17.0", + "@eslint/plugin-kit": "^0.4.1", + "github-slugger": "^2.0.0", + "mdast-util-from-markdown": "^2.0.2", + "mdast-util-frontmatter": "^2.0.1", + "mdast-util-gfm": "^3.1.0", + "micromark-extension-frontmatter": "^2.0.0", + "micromark-extension-gfm": "^3.0.0", + "micromark-util-normalize-identifier": "^2.0.1" }, "engines": { - "node": ">= 8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz", + "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.4" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@monaco-editor/loader": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.7.0.tgz", + "integrity": "sha512-gIwR1HrJrrx+vfyOhYmCZ0/JcWqG5kbfG7+d3f/C1LXk2EvzAbHSg3MQ5lO2sMlo9izoAZ04shohfKLVT6crVA==", + "license": "MIT", + "dependencies": { + "state-local": "^1.0.6" + } + }, + "node_modules/@monaco-editor/react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.7.0.tgz", + "integrity": "sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==", + "license": "MIT", + "dependencies": { + "@monaco-editor/loader": "^1.5.0" + }, + "peerDependencies": { + "monaco-editor": ">= 0.25.0 < 1", + "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" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" } }, "node_modules/@nodelib/fs.stat": { @@ -956,16 +1433,117 @@ "node": ">= 8" } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "node_modules/@oxlint/darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/@oxlint/darwin-arm64/-/darwin-arm64-1.33.0.tgz", + "integrity": "sha512-PmEQDLHAxiAdyttQ1ZWXd+5VpHLbHf3FTMJL9bg5TZamDnhNiW/v0Pamv3MTAdymnoDI3H8IVLAN/SAseV/adw==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", "optional": true, - "engines": { - "node": ">=14" - } + "os": [ + "darwin" + ] + }, + "node_modules/@oxlint/darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/@oxlint/darwin-x64/-/darwin-x64-1.33.0.tgz", + "integrity": "sha512-2R9aH3kR0X2M30z5agGikv3tfNTi8/uLhU5/tYktu33VGUXpbf0OLZSlD25UEuwOKAlf3RVtzV5oDyjoq93JuQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oxlint/linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/@oxlint/linux-arm64-gnu/-/linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-yb/k8GaMDgnX2LyO6km33kKItZ/n573SlbiHBBFU2HmeU7tzEHL5jHkHQXXcysUkapmqHd7UsDhOZDqPmXaQRg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxlint/linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/@oxlint/linux-arm64-musl/-/linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-03pt9IO1C4ZfVOW6SQiOK26mzklAhLM3Kc79OXpX1kgZRlxk+rvFoMhlgCOzn7tEdrEgbePkBoxNnwDnJDFqJQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxlint/linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/@oxlint/linux-x64-gnu/-/linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-Z7ImLWM50FoVXzYvyxUQ+QwBkBfRyK4YdLEGonyAGMp7iT3DksonDaTK9ODnJ1qHyAyAZCvuqXD7AEDsDvzDbA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxlint/linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/@oxlint/linux-x64-musl/-/linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-idb55Uzu5kkqqpMiVUfI9nP7zOqPZinQKsIRQAIU40wILcf/ijvhNZKIu3ucDMmye0n6IWOaSnxIRL5W2fNoUQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxlint/win32-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/@oxlint/win32-arm64/-/win32-arm64-1.33.0.tgz", + "integrity": "sha512-wKKFt7cubfrLelNzdmDsNSmtBrlSUe1fWus587+uSxDZdpFbQ7liU0gsUlCbcHvym0H1Tc2O3K3cnLrgQORLPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@oxlint/win32-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/@oxlint/win32-x64/-/win32-x64-1.33.0.tgz", + "integrity": "sha512-ReyR8rNHjKNnO7dxGny9RCPELRAdhm3y780FNBcA07E1wvxSCkB+Mn5db0Pa5bRmxrsU/MTZ/aaBFa+ERXDdXw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, "node_modules/@radix-ui/primitive": { "version": "1.1.3", @@ -1638,9 +2216,9 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.2.tgz", - "integrity": "sha512-yDPzwsgiFO26RJA4nZo8I+xqzh7sJTZIWQOxn+/XOdPE31lAvLIYCKqjV+lNH/vxE2L2iH3plKxDCRK6i+CwhA==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.5.tgz", + "integrity": "sha512-iDGS/h7D8t7tvZ1t6+WPK04KD0MwzLZrG0se1hzBjSi5fyxlsiggoJHwh18PCFNn7tG43OWb6pdZ6Y+rMlmyNQ==", "cpu": [ "arm" ], @@ -1652,9 +2230,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.2.tgz", - "integrity": "sha512-k8FontTxIE7b0/OGKeSN5B6j25EuppBcWM33Z19JoVT7UTXFSo3D9CdU39wGTeb29NO3XxpMNauh09B+Ibw+9g==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.5.tgz", + "integrity": "sha512-wrSAViWvZHBMMlWk6EJhvg8/rjxzyEhEdgfMMjREHEq11EtJ6IP6yfcCH57YAEca2Oe3FNCE9DSTgU70EIGmVw==", "cpu": [ "arm64" ], @@ -1666,9 +2244,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.2.tgz", - "integrity": "sha512-A6s4gJpomNBtJ2yioj8bflM2oogDwzUiMl2yNJ2v9E7++sHrSrsQ29fOfn5DM/iCzpWcebNYEdXpaK4tr2RhfQ==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.5.tgz", + "integrity": "sha512-S87zZPBmRO6u1YXQLwpveZm4JfPpAa6oHBX7/ghSiGH3rz/KDgAu1rKdGutV+WUI6tKDMbaBJomhnT30Y2t4VQ==", "cpu": [ "arm64" ], @@ -1680,9 +2258,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.2.tgz", - "integrity": "sha512-e6XqVmXlHrBlG56obu9gDRPW3O3hLxpwHpLsBJvuI8qqnsrtSZ9ERoWUXtPOkY8c78WghyPHZdmPhHLWNdAGEw==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.5.tgz", + "integrity": "sha512-YTbnsAaHo6VrAczISxgpTva8EkfQus0VPEVJCEaboHtZRIb6h6j0BNxRBOwnDciFTZLDPW5r+ZBmhL/+YpTZgA==", "cpu": [ "x64" ], @@ -1694,9 +2272,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.2.tgz", - "integrity": "sha512-v0E9lJW8VsrwPux5Qe5CwmH/CF/2mQs6xU1MF3nmUxmZUCHazCjLgYvToOk+YuuUqLQBio1qkkREhxhc656ViA==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.5.tgz", + "integrity": "sha512-1T8eY2J8rKJWzaznV7zedfdhD1BqVs1iqILhmHDq/bqCUZsrMt+j8VCTHhP0vdfbHK3e1IQ7VYx3jlKqwlf+vw==", "cpu": [ "arm64" ], @@ -1708,9 +2286,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.2.tgz", - "integrity": "sha512-ClAmAPx3ZCHtp6ysl4XEhWU69GUB1D+s7G9YjHGhIGCSrsg00nEGRRZHmINYxkdoJehde8VIsDC5t9C0gb6yqA==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.5.tgz", + "integrity": "sha512-sHTiuXyBJApxRn+VFMaw1U+Qsz4kcNlxQ742snICYPrY+DDL8/ZbaC4DVIB7vgZmp3jiDaKA0WpBdP0aqPJoBQ==", "cpu": [ "x64" ], @@ -1722,9 +2300,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.2.tgz", - "integrity": "sha512-EPlb95nUsz6Dd9Qy13fI5kUPXNSljaG9FiJ4YUGU1O/Q77i5DYFW5KR8g1OzTcdZUqQQ1KdDqsTohdFVwCwjqg==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.5.tgz", + "integrity": "sha512-dV3T9MyAf0w8zPVLVBptVlzaXxka6xg1f16VAQmjg+4KMSTWDvhimI/Y6mp8oHwNrmnmVl9XxJ/w/mO4uIQONA==", "cpu": [ "arm" ], @@ -1736,9 +2314,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.2.tgz", - "integrity": "sha512-BOmnVW+khAUX+YZvNfa0tGTEMVVEerOxN0pDk2E6N6DsEIa2Ctj48FOMfNDdrwinocKaC7YXUZ1pHlKpnkja/Q==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.5.tgz", + "integrity": "sha512-wIGYC1x/hyjP+KAu9+ewDI+fi5XSNiUi9Bvg6KGAh2TsNMA3tSEs+Sh6jJ/r4BV/bx/CyWu2ue9kDnIdRyafcQ==", "cpu": [ "arm" ], @@ -1750,9 +2328,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.2.tgz", - "integrity": "sha512-Xt2byDZ+6OVNuREgBXr4+CZDJtrVso5woFtpKdGPhpTPHcNG7D8YXeQzpNbFRxzTVqJf7kvPMCub/pcGUWgBjA==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.5.tgz", + "integrity": "sha512-Y+qVA0D9d0y2FRNiG9oM3Hut/DgODZbU9I8pLLPwAsU0tUKZ49cyV1tzmB/qRbSzGvY8lpgGkJuMyuhH7Ma+Vg==", "cpu": [ "arm64" ], @@ -1764,9 +2342,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.2.tgz", - "integrity": "sha512-+LdZSldy/I9N8+klim/Y1HsKbJ3BbInHav5qE9Iy77dtHC/pibw1SR/fXlWyAk0ThnpRKoODwnAuSjqxFRDHUQ==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.5.tgz", + "integrity": "sha512-juaC4bEgJsyFVfqhtGLz8mbopaWD+WeSOYr5E16y+1of6KQjc0BpwZLuxkClqY1i8sco+MdyoXPNiCkQou09+g==", "cpu": [ "arm64" ], @@ -1778,9 +2356,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.2.tgz", - "integrity": "sha512-8ms8sjmyc1jWJS6WdNSA23rEfdjWB30LH8Wqj0Cqvv7qSHnvw6kgMMXRdop6hkmGPlyYBdRPkjJnj3KCUHV/uQ==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.5.tgz", + "integrity": "sha512-rIEC0hZ17A42iXtHX+EPJVL/CakHo+tT7W0pbzdAGuWOt2jxDFh7A/lRhsNHBcqL4T36+UiAgwO8pbmn3dE8wA==", "cpu": [ "loong64" ], @@ -1792,9 +2370,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.2.tgz", - "integrity": "sha512-3HRQLUQbpBDMmzoxPJYd3W6vrVHOo2cVW8RUo87Xz0JPJcBLBr5kZ1pGcQAhdZgX9VV7NbGNipah1omKKe23/g==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.5.tgz", + "integrity": "sha512-T7l409NhUE552RcAOcmJHj3xyZ2h7vMWzcwQI0hvn5tqHh3oSoclf9WgTl+0QqffWFG8MEVZZP1/OBglKZx52Q==", "cpu": [ "ppc64" ], @@ -1806,9 +2384,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.2.tgz", - "integrity": "sha512-fMjKi+ojnmIvhk34gZP94vjogXNNUKMEYs+EDaB/5TG/wUkoeua7p7VCHnE6T2Tx+iaghAqQX8teQzcvrYpaQA==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.5.tgz", + "integrity": "sha512-7OK5/GhxbnrMcxIFoYfhV/TkknarkYC1hqUw1wU2xUN3TVRLNT5FmBv4KkheSG2xZ6IEbRAhTooTV2+R5Tk0lQ==", "cpu": [ "riscv64" ], @@ -1820,9 +2398,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.2.tgz", - "integrity": "sha512-XuGFGU+VwUUV5kLvoAdi0Wz5Xbh2SrjIxCtZj6Wq8MDp4bflb/+ThZsVxokM7n0pcbkEr2h5/pzqzDYI7cCgLQ==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.5.tgz", + "integrity": "sha512-GwuDBE/PsXaTa76lO5eLJTyr2k8QkPipAyOrs4V/KJufHCZBJ495VCGJol35grx9xryk4V+2zd3Ri+3v7NPh+w==", "cpu": [ "riscv64" ], @@ -1834,9 +2412,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.2.tgz", - "integrity": "sha512-w6yjZF0P+NGzWR3AXWX9zc0DNEGdtvykB03uhonSHMRa+oWA6novflo2WaJr6JZakG2ucsyb+rvhrKac6NIy+w==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.5.tgz", + "integrity": "sha512-IAE1Ziyr1qNfnmiQLHBURAD+eh/zH1pIeJjeShleII7Vj8kyEm2PF77o+lf3WTHDpNJcu4IXJxNO0Zluro8bOw==", "cpu": [ "s390x" ], @@ -1848,9 +2426,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.2.tgz", - "integrity": "sha512-yo8d6tdfdeBArzC7T/PnHd7OypfI9cbuZzPnzLJIyKYFhAQ8SvlkKtKBMbXDxe1h03Rcr7u++nFS7tqXz87Gtw==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.5.tgz", + "integrity": "sha512-Pg6E+oP7GvZ4XwgRJBuSXZjcqpIW3yCBhK4BcsANvb47qMvAbCjR6E+1a/U2WXz1JJxp9/4Dno3/iSJLcm5auw==", "cpu": [ "x64" ], @@ -1862,9 +2440,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.2.tgz", - "integrity": "sha512-ah59c1YkCxKExPP8O9PwOvs+XRLKwh/mV+3YdKqQ5AMQ0r4M4ZDuOrpWkUaqO7fzAHdINzV9tEVu8vNw48z0lA==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.5.tgz", + "integrity": "sha512-txGtluxDKTxaMDzUduGP0wdfng24y1rygUMnmlUJ88fzCCULCLn7oE5kb2+tRB+MWq1QDZT6ObT5RrR8HFRKqg==", "cpu": [ "x64" ], @@ -1876,9 +2454,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.2.tgz", - "integrity": "sha512-4VEd19Wmhr+Zy7hbUsFZ6YXEiP48hE//KPLCSVNY5RMGX2/7HZ+QkN55a3atM1C/BZCGIgqN+xrVgtdak2S9+A==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.5.tgz", + "integrity": "sha512-3DFiLPnTxiOQV993fMc+KO8zXHTcIjgaInrqlG8zDp1TlhYl6WgrOHuJkJQ6M8zHEcntSJsUp1XFZSY8C1DYbg==", "cpu": [ "arm64" ], @@ -1890,9 +2468,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.2.tgz", - "integrity": "sha512-IlbHFYc/pQCgew/d5fslcy1KEaYVCJ44G8pajugd8VoOEI8ODhtb/j8XMhLpwHCMB3yk2J07ctup10gpw2nyMA==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.5.tgz", + "integrity": "sha512-nggc/wPpNTgjGg75hu+Q/3i32R00Lq1B6N1DO7MCU340MRKL3WZJMjA9U4K4gzy3dkZPXm9E1Nc81FItBVGRlA==", "cpu": [ "arm64" ], @@ -1904,9 +2482,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.2.tgz", - "integrity": "sha512-lNlPEGgdUfSzdCWU176ku/dQRnA7W+Gp8d+cWv73jYrb8uT7HTVVxq62DUYxjbaByuf1Yk0RIIAbDzp+CnOTFg==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.5.tgz", + "integrity": "sha512-U/54pTbdQpPLBdEzCT6NBCFAfSZMvmjr0twhnD9f4EIvlm9wy3jjQ38yQj1AGznrNO65EWQMgm/QUjuIVrYF9w==", "cpu": [ "ia32" ], @@ -1918,9 +2496,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.2.tgz", - "integrity": "sha512-S6YojNVrHybQis2lYov1sd+uj7K0Q05NxHcGktuMMdIQ2VixGwAfbJ23NnlvvVV1bdpR2m5MsNBViHJKcA4ADw==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.5.tgz", + "integrity": "sha512-2NqKgZSuLH9SXBBV2dWNRCZmocgSOx8OJSdpRaEcRlIfX8YrKxUT6z0F1NpvDVhOsl190UFTRh2F2WDWWCYp3A==", "cpu": [ "x64" ], @@ -1932,9 +2510,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.2.tgz", - "integrity": "sha512-k+/Rkcyx//P6fetPoLMb8pBeqJBNGx81uuf7iljX9++yNBVRDQgD04L+SVXmXmh5ZP4/WOp4mWF0kmi06PW2tA==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.5.tgz", + "integrity": "sha512-JRpZUhCfhZ4keB5v0fe02gQJy05GqboPOaxvjugW04RLSYYoB/9t2lx2u/tMs/Na/1NXfY8QYjgRljRpN+MjTQ==", "cpu": [ "x64" ], @@ -1945,10 +2523,30 @@ "win32" ] }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tailwindcss/typography": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.19.tgz", + "integrity": "sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "6.0.10" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" + } + }, "node_modules/@tanstack/query-core": { - "version": "5.90.8", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.8.tgz", - "integrity": "sha512-4E0RP/0GJCxSNiRF2kAqE/LQkTJVlL/QNU7gIJSptaseV9HP6kOuA+N11y4bZKZxa3QopK3ZuewwutHx6DqDXQ==", + "version": "5.90.12", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.12.tgz", + "integrity": "sha512-T1/8t5DhV/SisWjDnaiU2drl6ySvsHj1bHBCWNXd+/T+Hh1cf6JodyEYMd5sgwm+b/mETT4EV3H+zCVczCU5hg==", "license": "MIT", "funding": { "type": "github", @@ -1956,12 +2554,12 @@ } }, "node_modules/@tanstack/react-query": { - "version": "5.90.8", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.8.tgz", - "integrity": "sha512-/3b9QGzkf4rE5/miL6tyhldQRlLXzMHcySOm/2Tm2OLEFE9P1ImkH0+OviDBSvyAvtAOJocar5xhd7vxdLi3aQ==", + "version": "5.90.12", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.12.tgz", + "integrity": "sha512-graRZspg7EoEaw0a8faiUASCyJrqjKPdqJ9EwuDRUF9mEYJ1YPczI9H+/agJ0mOJkPCJDk0lsz5QTrLZ/jQ2rg==", "license": "MIT", "dependencies": { - "@tanstack/query-core": "5.90.8" + "@tanstack/query-core": "5.90.12" }, "funding": { "type": "github", @@ -1972,9 +2570,9 @@ } }, "node_modules/@tauri-apps/api": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.9.0.tgz", - "integrity": "sha512-qD5tMjh7utwBk9/5PrTA/aGr3i5QaJ/Mlt7p8NilQ45WgbifUNPyKWsA63iQ8YfQq6R8ajMapU+/Q8nMcPRLNw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.9.1.tgz", + "integrity": "sha512-IGlhP6EivjXHepbBic618GOmiWe4URJiIeZFlB7x3czM0yDHHYviH1Xvoiv4FefdkQtn6v7TuwWCRfOGdnVUGw==", "license": "Apache-2.0 OR MIT", "funding": { "type": "opencollective", @@ -1982,9 +2580,9 @@ } }, "node_modules/@tauri-apps/cli": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.9.4.tgz", - "integrity": "sha512-pvylWC9QckrOS9ATWXIXcgu7g2hKK5xTL5ZQyZU/U0n9l88SEFGcWgLQNa8WZmd+wWIOWhkxOFcOl3i6ubDNNw==", + "version": "2.9.6", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.9.6.tgz", + "integrity": "sha512-3xDdXL5omQ3sPfBfdC8fCtDKcnyV7OqyzQgfyT5P3+zY6lcPqIYKQBvUasNvppi21RSdfhy44ttvJmftb0PCDw==", "dev": true, "license": "Apache-2.0 OR MIT", "bin": { @@ -1998,23 +2596,23 @@ "url": "https://opencollective.com/tauri" }, "optionalDependencies": { - "@tauri-apps/cli-darwin-arm64": "2.9.4", - "@tauri-apps/cli-darwin-x64": "2.9.4", - "@tauri-apps/cli-linux-arm-gnueabihf": "2.9.4", - "@tauri-apps/cli-linux-arm64-gnu": "2.9.4", - "@tauri-apps/cli-linux-arm64-musl": "2.9.4", - "@tauri-apps/cli-linux-riscv64-gnu": "2.9.4", - "@tauri-apps/cli-linux-x64-gnu": "2.9.4", - "@tauri-apps/cli-linux-x64-musl": "2.9.4", - "@tauri-apps/cli-win32-arm64-msvc": "2.9.4", - "@tauri-apps/cli-win32-ia32-msvc": "2.9.4", - "@tauri-apps/cli-win32-x64-msvc": "2.9.4" + "@tauri-apps/cli-darwin-arm64": "2.9.6", + "@tauri-apps/cli-darwin-x64": "2.9.6", + "@tauri-apps/cli-linux-arm-gnueabihf": "2.9.6", + "@tauri-apps/cli-linux-arm64-gnu": "2.9.6", + "@tauri-apps/cli-linux-arm64-musl": "2.9.6", + "@tauri-apps/cli-linux-riscv64-gnu": "2.9.6", + "@tauri-apps/cli-linux-x64-gnu": "2.9.6", + "@tauri-apps/cli-linux-x64-musl": "2.9.6", + "@tauri-apps/cli-win32-arm64-msvc": "2.9.6", + "@tauri-apps/cli-win32-ia32-msvc": "2.9.6", + "@tauri-apps/cli-win32-x64-msvc": "2.9.6" } }, "node_modules/@tauri-apps/cli-darwin-arm64": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.9.4.tgz", - "integrity": "sha512-9rHkMVtbMhe0AliVbrGpzMahOBg3rwV46JYRELxR9SN6iu1dvPOaMaiC4cP6M/aD1424ziXnnMdYU06RAH8oIw==", + "version": "2.9.6", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.9.6.tgz", + "integrity": "sha512-gf5no6N9FCk1qMrti4lfwP77JHP5haASZgVbBgpZG7BUepB3fhiLCXGUK8LvuOjP36HivXewjg72LTnPDScnQQ==", "cpu": [ "arm64" ], @@ -2029,9 +2627,9 @@ } }, "node_modules/@tauri-apps/cli-darwin-x64": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.9.4.tgz", - "integrity": "sha512-VT9ymNuT06f5TLjCZW2hfSxbVtZDhORk7CDUDYiq5TiSYQdxkl8MVBy0CCFFcOk4QAkUmqmVUA9r3YZ/N/vPRQ==", + "version": "2.9.6", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.9.6.tgz", + "integrity": "sha512-oWh74WmqbERwwrwcueJyY6HYhgCksUc6NT7WKeXyrlY/FPmNgdyQAgcLuTSkhRFuQ6zh4Np1HZpOqCTpeZBDcw==", "cpu": [ "x64" ], @@ -2046,9 +2644,9 @@ } }, "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.9.4.tgz", - "integrity": "sha512-tTWkEPig+2z3Rk0zqZYfjUYcgD+aSm72wdrIhdYobxbQZOBw0zfn50YtWv+av7bm0SHvv75f0l7JuwgZM1HFow==", + "version": "2.9.6", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.9.6.tgz", + "integrity": "sha512-/zde3bFroFsNXOHN204DC2qUxAcAanUjVXXSdEGmhwMUZeAQalNj5cz2Qli2elsRjKN/hVbZOJj0gQ5zaYUjSg==", "cpu": [ "arm" ], @@ -2063,9 +2661,9 @@ } }, "node_modules/@tauri-apps/cli-linux-arm64-gnu": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.9.4.tgz", - "integrity": "sha512-ql6vJ611qoqRYHxkKPnb2vHa27U+YRKRmIpLMMBeZnfFtZ938eao7402AQCH1mO2+/8ioUhbpy9R/ZcLTXVmkg==", + "version": "2.9.6", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.9.6.tgz", + "integrity": "sha512-pvbljdhp9VOo4RnID5ywSxgBs7qiylTPlK56cTk7InR3kYSTJKYMqv/4Q/4rGo/mG8cVppesKIeBMH42fw6wjg==", "cpu": [ "arm64" ], @@ -2080,9 +2678,9 @@ } }, "node_modules/@tauri-apps/cli-linux-arm64-musl": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.9.4.tgz", - "integrity": "sha512-vg7yNn7ICTi6hRrcA/6ff2UpZQP7un3xe3SEld5QM0prgridbKAiXGaCKr3BnUBx/rGXegQlD/wiLcWdiiraSw==", + "version": "2.9.6", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.9.6.tgz", + "integrity": "sha512-02TKUndpodXBCR0oP//6dZWGYcc22Upf2eP27NvC6z0DIqvkBBFziQUcvi2n6SrwTRL0yGgQjkm9K5NIn8s6jw==", "cpu": [ "arm64" ], @@ -2097,9 +2695,9 @@ } }, "node_modules/@tauri-apps/cli-linux-riscv64-gnu": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.9.4.tgz", - "integrity": "sha512-l8L+3VxNk6yv5T/Z/gv5ysngmIpsai40B9p6NQQyqYqxImqYX37pqREoEBl1YwG7szGnDibpWhidPrWKR59OJA==", + "version": "2.9.6", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.9.6.tgz", + "integrity": "sha512-fmp1hnulbqzl1GkXl4aTX9fV+ubHw2LqlLH1PE3BxZ11EQk+l/TmiEongjnxF0ie4kV8DQfDNJ1KGiIdWe1GvQ==", "cpu": [ "riscv64" ], @@ -2114,9 +2712,9 @@ } }, "node_modules/@tauri-apps/cli-linux-x64-gnu": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.9.4.tgz", - "integrity": "sha512-PepPhCXc/xVvE3foykNho46OmCyx47E/aG676vKTVp+mqin5d+IBqDL6wDKiGNT5OTTxKEyNlCQ81Xs2BQhhqA==", + "version": "2.9.6", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.9.6.tgz", + "integrity": "sha512-vY0le8ad2KaV1PJr+jCd8fUF9VOjwwQP/uBuTJvhvKTloEwxYA/kAjKK9OpIslGA9m/zcnSo74czI6bBrm2sYA==", "cpu": [ "x64" ], @@ -2131,9 +2729,9 @@ } }, "node_modules/@tauri-apps/cli-linux-x64-musl": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.9.4.tgz", - "integrity": "sha512-zcd1QVffh5tZs1u1SCKUV/V7RRynebgYUNWHuV0FsIF1MjnULUChEXhAhug7usCDq4GZReMJOoXa6rukEozWIw==", + "version": "2.9.6", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.9.6.tgz", + "integrity": "sha512-TOEuB8YCFZTWVDzsO2yW0+zGcoMiPPwcUgdnW1ODnmgfwccpnihDRoks+ABT1e3fHb1ol8QQWsHSCovb3o2ENQ==", "cpu": [ "x64" ], @@ -2148,9 +2746,9 @@ } }, "node_modules/@tauri-apps/cli-win32-arm64-msvc": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.9.4.tgz", - "integrity": "sha512-/7ZhnP6PY04bEob23q8MH/EoDISdmR1wuNm0k9d5HV7TDMd2GGCDa8dPXA4vJuglJKXIfXqxFmZ4L+J+MO42+w==", + "version": "2.9.6", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.9.6.tgz", + "integrity": "sha512-ujmDGMRc4qRLAnj8nNG26Rlz9klJ0I0jmZs2BPpmNNf0gM/rcVHhqbEkAaHPTBVIrtUdf7bGvQAD2pyIiUrBHQ==", "cpu": [ "arm64" ], @@ -2165,9 +2763,9 @@ } }, "node_modules/@tauri-apps/cli-win32-ia32-msvc": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.9.4.tgz", - "integrity": "sha512-1LmAfaC4Cq+3O1Ir1ksdhczhdtFSTIV51tbAGtbV/mr348O+M52A/xwCCXQank0OcdBxy5BctqkMtuZnQvA8uQ==", + "version": "2.9.6", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.9.6.tgz", + "integrity": "sha512-S4pT0yAJgFX8QRCyKA1iKjZ9Q/oPjCZf66A/VlG5Yw54Nnr88J1uBpmenINbXxzyhduWrIXBaUbEY1K80ZbpMg==", "cpu": [ "ia32" ], @@ -2182,9 +2780,9 @@ } }, "node_modules/@tauri-apps/cli-win32-x64-msvc": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.9.4.tgz", - "integrity": "sha512-EdYd4c9wGvtPB95kqtEyY+bUR+k4kRw3IA30mAQ1jPH6z57AftT8q84qwv0RDp6kkEqOBKxeInKfqi4BESYuqg==", + "version": "2.9.6", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.9.6.tgz", + "integrity": "sha512-ldWuWSSkWbKOPjQMJoYVj9wLHcOniv7diyI5UAJ4XsBdtaFB0pKHQsqw/ItUma0VXGC7vB4E9fZjivmxur60aw==", "cpu": [ "x64" ], @@ -2216,7 +2814,89 @@ "@tauri-apps/api": "^2.8.0" } }, - "node_modules/@types/babel__core": { + "node_modules/@testing-library/dom": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", + "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "picocolors": "^1.1.1", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/react": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.1.tgz", + "integrity": "sha512-gr4KtAWqIOQoucWYD/f6ki+j5chXfcPc74Col/6poTyqTmn7zRmodWahWRCp8tYd+GMqBonw6hstNzqjbs6gjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", @@ -2261,17 +2941,83 @@ "@babel/types": "^7.28.2" } }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true, "license": "MIT" }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, "node_modules/@types/node": { - "version": "20.19.25", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.25.tgz", - "integrity": "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==", + "version": "20.19.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.27.tgz", + "integrity": "sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==", "dev": true, "license": "MIT", "dependencies": { @@ -2289,18 +3035,16 @@ "version": "15.7.15", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", - "devOptional": true, "license": "MIT" }, "node_modules/@types/react": { - "version": "18.3.26", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.26.tgz", - "integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==", - "devOptional": true, + "version": "18.3.27", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", + "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", "license": "MIT", "dependencies": { "@types/prop-types": "*", - "csstype": "^3.0.2" + "csstype": "^3.2.2" } }, "node_modules/@types/react-dom": { @@ -2313,842 +3057,834 @@ "@types/react": "^18.0.0" } }, - "node_modules/@vitejs/plugin-react": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", - "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.50.0.tgz", + "integrity": "sha512-O7QnmOXYKVtPrfYzMolrCTfkezCJS9+ljLdKW/+DCvRsc3UAz+sbH6Xcsv7p30+0OwUbeWfUDAQE0vpabZ3QLg==", "dev": true, "license": "MIT", "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" + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.50.0", + "@typescript-eslint/type-utils": "8.50.0", + "@typescript-eslint/utils": "8.50.0", + "@typescript-eslint/visitor-keys": "8.50.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" - } - }, - "node_modules/@xterm/addon-clipboard": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@xterm/addon-clipboard/-/addon-clipboard-0.1.0.tgz", - "integrity": "sha512-zdoM7p53T5sv/HbRTyp4hY0kKmEQ3MZvAvEtiXqNIHc/JdpqwByCtsTaQF5DX2n4hYdXRPO4P/eOS0QEhX1nPw==", - "license": "MIT", - "dependencies": { - "js-base64": "^3.7.5" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@xterm/xterm": "^5.4.0" + "@typescript-eslint/parser": "^8.50.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/@xterm/addon-fit": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/@xterm/addon-fit/-/addon-fit-0.10.0.tgz", - "integrity": "sha512-UFYkDm4HUahf2lnEyHvio51TNGiLK66mqP2JoATy7hRZeXaGMRDr00JiSF7m63vR5WKATF605yEggJKsw0JpMQ==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, "license": "MIT", - "peerDependencies": { - "@xterm/xterm": "^5.0.0" + "engines": { + "node": ">= 4" } }, - "node_modules/@xterm/addon-ligatures": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@xterm/addon-ligatures/-/addon-ligatures-0.9.0.tgz", - "integrity": "sha512-zVV1AHV1SIm/rdzR5VDPyg+qUnR1SjH4H75iXiB7r6YDa1yEHIqc/EwnUIwz+yeeZozkh8hjbH80L7luEgtxtQ==", + "node_modules/@typescript-eslint/parser": { + "version": "8.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.50.0.tgz", + "integrity": "sha512-6/cmF2piao+f6wSxUsJLZjck7OQsYyRtcOZS02k7XINSNlz93v6emM8WutDQSXnroG2xwYlEVHJI+cPA7CPM3Q==", + "dev": true, "license": "MIT", "dependencies": { - "font-finder": "^1.1.0", - "font-ligatures": "^1.4.1" + "@typescript-eslint/scope-manager": "8.50.0", + "@typescript-eslint/types": "8.50.0", + "@typescript-eslint/typescript-estree": "8.50.0", + "@typescript-eslint/visitor-keys": "8.50.0", + "debug": "^4.3.4" }, "engines": { - "node": ">8.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@xterm/xterm": "^5.0.0" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/@xterm/addon-search": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@xterm/addon-search/-/addon-search-0.15.0.tgz", - "integrity": "sha512-ZBZKLQ+EuKE83CqCmSSz5y1tx+aNOCUaA7dm6emgOX+8J9H1FWXZyrKfzjwzV+V14TV3xToz1goIeRhXBS5qjg==", + "node_modules/@typescript-eslint/project-service": { + "version": "8.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.50.0.tgz", + "integrity": "sha512-Cg/nQcL1BcoTijEWyx4mkVC56r8dj44bFDvBdygifuS20f3OZCHmFbjF34DPSi07kwlFvqfv/xOLnJ5DquxSGQ==", + "dev": true, "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.50.0", + "@typescript-eslint/types": "^8.50.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, "peerDependencies": { - "@xterm/xterm": "^5.0.0" + "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/@xterm/addon-unicode11": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@xterm/addon-unicode11/-/addon-unicode11-0.8.0.tgz", - "integrity": "sha512-LxinXu8SC4OmVa6FhgwsVCBZbr8WoSGzBl2+vqe8WcQ6hb1r6Gj9P99qTNdPiFPh4Ceiu2pC8xukZ6+2nnh49Q==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.50.0.tgz", + "integrity": "sha512-xCwfuCZjhIqy7+HKxBLrDVT5q/iq7XBVBXLn57RTIIpelLtEIZHXAF/Upa3+gaCpeV1NNS5Z9A+ID6jn50VD4A==", + "dev": true, "license": "MIT", - "peerDependencies": { - "@xterm/xterm": "^5.0.0" + "dependencies": { + "@typescript-eslint/types": "8.50.0", + "@typescript-eslint/visitor-keys": "8.50.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@xterm/addon-web-links": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@xterm/addon-web-links/-/addon-web-links-0.11.0.tgz", - "integrity": "sha512-nIHQ38pQI+a5kXnRaTgwqSHnX7KE6+4SVoceompgHL26unAxdfP6IPqUTSYPQgSwM56hsElfoNrrW5V7BUED/Q==", + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.50.0.tgz", + "integrity": "sha512-vxd3G/ybKTSlm31MOA96gqvrRGv9RJ7LGtZCn2Vrc5htA0zCDvcMqUkifcjrWNNKXHUU3WCkYOzzVSFBd0wa2w==", + "dev": true, "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, "peerDependencies": { - "@xterm/xterm": "^5.0.0" + "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/@xterm/addon-webgl": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@xterm/addon-webgl/-/addon-webgl-0.18.0.tgz", - "integrity": "sha512-xCnfMBTI+/HKPdRnSOHaJDRqEpq2Ugy8LEj9GiY4J3zJObo3joylIFaMvzBwbYRg8zLtkO0KQaStCeSfoaI2/w==", + "node_modules/@typescript-eslint/type-utils": { + "version": "8.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.50.0.tgz", + "integrity": "sha512-7OciHT2lKCewR0mFoBrvZJ4AXTMe/sYOe87289WAViOocEmDjjv8MvIOT2XESuKj9jp8u3SZYUSh89QA4S1kQw==", + "dev": true, "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.50.0", + "@typescript-eslint/typescript-estree": "8.50.0", + "@typescript-eslint/utils": "8.50.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, "peerDependencies": { - "@xterm/xterm": "^5.0.0" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/@xterm/xterm": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz", - "integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==", - "license": "MIT" - }, - "node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "node_modules/@typescript-eslint/types": { + "version": "8.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.50.0.tgz", + "integrity": "sha512-iX1mgmGrXdANhhITbpp2QQM2fGehBse9LbTf0sidWK6yg/NE+uhV5dfU1g6EYPlcReYmkE9QLPq/2irKAmtS9w==", "dev": true, "license": "MIT", "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.50.0.tgz", + "integrity": "sha512-W7SVAGBR/IX7zm1t70Yujpbk+zdPq/u4soeFSknWFdXIFuWsBGBOUu/Tn/I6KHSKvSh91OiMuaSnYp3mtPt5IQ==", "dev": true, "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.50.0", + "@typescript-eslint/tsconfig-utils": "8.50.0", + "@typescript-eslint/types": "8.50.0", + "@typescript-eslint/visitor-keys": "8.50.0", + "debug": "^4.3.4", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.1.0" + }, "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "license": "ISC", "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">= 8" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, - "license": "MIT" - }, - "node_modules/aria-hidden": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", - "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", - "license": "MIT", - "dependencies": { - "tslib": "^2.0.0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, "engines": { "node": ">=10" } }, - "node_modules/autoprefixer": { - "version": "10.4.22", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.22.tgz", - "integrity": "sha512-ARe0v/t9gO28Bznv6GgqARmVqcWOV3mfgUPn9becPHMiD3o9BwlRgaeccZnwTpZ7Zwqrm+c1sUSsMxIzQzc8Xg==", + "node_modules/@typescript-eslint/utils": { + "version": "8.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.50.0.tgz", + "integrity": "sha512-87KgUXET09CRjGCi2Ejxy3PULXna63/bMYv72tCAlDJC3Yqwln0HiFJ3VJMst2+mEtNtZu5oFvX4qJGjKsnAgg==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], "license": "MIT", "dependencies": { - "browserslist": "^4.27.0", - "caniuse-lite": "^1.0.30001754", - "fraction.js": "^5.3.4", - "normalize-range": "^0.1.2", - "picocolors": "^1.1.1", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.50.0", + "@typescript-eslint/types": "8.50.0", + "@typescript-eslint/typescript-estree": "8.50.0" }, "engines": { - "node": "^10 || ^12 || >=14" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/baseline-browser-mapping": { - "version": "2.8.28", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.28.tgz", - "integrity": "sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.js" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.50.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.50.0.tgz", + "integrity": "sha512-Xzmnb58+Db78gT/CCj/PVCvK+zxbnsw6F+O1oheYszJbBSdEjVhQi3C/Xttzxgi/GLmpvOggRs1RFpiJ8+c34Q==", "dev": true, "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.50.0", + "eslint-visitor-keys": "^4.2.1" + }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "license": "ISC" }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", "dev": true, "license": "MIT", "dependencies": { - "fill-range": "^7.1.1" + "@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" }, "engines": { - "node": ">=8" + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, - "node_modules/browserslist": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz", - "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==", + "node_modules/@vitest/expect": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.15.tgz", + "integrity": "sha512-Gfyva9/GxPAWXIWjyGDli9O+waHDC0Q0jaLdFP1qPAUUfo1FEXPXUfUkp3eZA0sSq340vPycSyOlYUeM15Ft1w==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.8.25", - "caniuse-lite": "^1.0.30001754", - "electron-to-chromium": "^1.5.249", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.1.4" - }, - "bin": { - "browserslist": "cli.js" + "@standard-schema/spec": "^1.0.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.0.15", + "@vitest/utils": "4.0.15", + "chai": "^6.2.1", + "tinyrainbow": "^3.0.3" }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "node_modules/@vitest/mocker": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.15.tgz", + "integrity": "sha512-CZ28GLfOEIFkvCFngN8Sfx5h+Se0zN+h4B7yOsPVCcgtiO7t5jt9xQh2E1UkFep+eb9fjyMfuC5gBypwb07fvQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001754", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001754.tgz", - "integrity": "sha512-x6OeBXueoAceOmotzx3PO4Zpt4rzpeIFsSr6AAePTZxSkXiYDUmpypEl7e2+8NCd9bD7bXjqyef8CJYPC1jfxg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + "dependencies": { + "@vitest/spy": "4.0.15", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" + "vite": { + "optional": true } - ], - "license": "CC-BY-4.0" + } }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "node_modules/@vitest/pretty-format": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.15.tgz", + "integrity": "sha512-SWdqR8vEv83WtZcrfLNqlqeQXlQLh2iilO1Wk1gv4eiHKjEzvgHb2OVc3mIPyhZE6F+CtfYjNlDJwP5MN6Km7A==", "dev": true, "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" + "tinyrainbow": "^3.0.3" }, "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "url": "https://opencollective.com/vitest" } }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/@vitest/runner": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.15.tgz", + "integrity": "sha512-+A+yMY8dGixUhHmNdPUxOh0la6uVzun86vAbuMT3hIDxMrAOmn5ILBHm8ajrqHE0t8R9T1dGnde1A5DTnmi3qw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "is-glob": "^4.0.1" + "@vitest/utils": "4.0.15", + "pathe": "^2.0.3" }, - "engines": { - "node": ">= 6" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/class-variance-authority": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", - "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", - "license": "Apache-2.0", + "node_modules/@vitest/snapshot": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.15.tgz", + "integrity": "sha512-A7Ob8EdFZJIBjLjeO0DZF4lqR6U7Ydi5/5LIZ0xcI+23lYlsYJAfGn8PrIWTYdZQRNnSRlzhg0zyGu37mVdy5g==", + "dev": true, + "license": "MIT", "dependencies": { - "clsx": "^2.1.1" + "@vitest/pretty-format": "4.0.15", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" }, "funding": { - "url": "https://polar.sh/cva" + "url": "https://opencollective.com/vitest" } }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "node_modules/@vitest/spy": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.15.tgz", + "integrity": "sha512-+EIjOJmnY6mIfdXtE/bnozKEvTC4Uczg19yeZ2vtCz5Yyb0QQ31QWVQ8hswJ3Ysx/K2EqaNsVanjr//2+P3FHw==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=6" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/cmdk": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.1.1.tgz", - "integrity": "sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==", + "node_modules/@vitest/utils": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.15.tgz", + "integrity": "sha512-HXjPW2w5dxhTD0dLwtYHDnelK3j8sR8cWIaLxr22evTyY6q8pRCjZSmhRWVjBaOVXChQd6AwMzi9pucorXCPZA==", + "dev": true, "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "^1.1.1", - "@radix-ui/react-dialog": "^1.1.6", - "@radix-ui/react-id": "^1.1.0", - "@radix-ui/react-primitive": "^2.0.2" + "@vitest/pretty-format": "4.0.15", + "tinyrainbow": "^3.0.3" }, - "peerDependencies": { - "react": "^18 || ^19 || ^19.0.0-rc", - "react-dom": "^18 || ^19 || ^19.0.0-rc" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "node_modules/@xterm/addon-clipboard": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@xterm/addon-clipboard/-/addon-clipboard-0.1.0.tgz", + "integrity": "sha512-zdoM7p53T5sv/HbRTyp4hY0kKmEQ3MZvAvEtiXqNIHc/JdpqwByCtsTaQF5DX2n4hYdXRPO4P/eOS0QEhX1nPw==", "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "js-base64": "^3.7.5" }, - "engines": { - "node": ">=7.0.0" + "peerDependencies": { + "@xterm/xterm": "^5.4.0" } }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, + "node_modules/@xterm/addon-fit": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@xterm/addon-fit/-/addon-fit-0.10.0.tgz", + "integrity": "sha512-UFYkDm4HUahf2lnEyHvio51TNGiLK66mqP2JoATy7hRZeXaGMRDr00JiSF7m63vR5WKATF605yEggJKsw0JpMQ==", "license": "MIT", - "engines": { - "node": ">= 6" + "peerDependencies": { + "@xterm/xterm": "^5.0.0" } }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, + "node_modules/@xterm/addon-ligatures": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@xterm/addon-ligatures/-/addon-ligatures-0.9.0.tgz", + "integrity": "sha512-zVV1AHV1SIm/rdzR5VDPyg+qUnR1SjH4H75iXiB7r6YDa1yEHIqc/EwnUIwz+yeeZozkh8hjbH80L7luEgtxtQ==", "license": "MIT", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "font-finder": "^1.1.0", + "font-ligatures": "^1.4.1" }, "engines": { - "node": ">= 8" + "node": ">8.0.0" + }, + "peerDependencies": { + "@xterm/xterm": "^5.0.0" } }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, + "node_modules/@xterm/addon-search": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@xterm/addon-search/-/addon-search-0.15.0.tgz", + "integrity": "sha512-ZBZKLQ+EuKE83CqCmSSz5y1tx+aNOCUaA7dm6emgOX+8J9H1FWXZyrKfzjwzV+V14TV3xToz1goIeRhXBS5qjg==", "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" + "peerDependencies": { + "@xterm/xterm": "^5.0.0" } }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, + "node_modules/@xterm/addon-unicode11": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@xterm/addon-unicode11/-/addon-unicode11-0.8.0.tgz", + "integrity": "sha512-LxinXu8SC4OmVa6FhgwsVCBZbr8WoSGzBl2+vqe8WcQ6hb1r6Gj9P99qTNdPiFPh4Ceiu2pC8xukZ6+2nnh49Q==", "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "peerDependencies": { + "@xterm/xterm": "^5.0.0" } }, - "node_modules/detect-node-es": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", - "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", - "license": "MIT" + "node_modules/@xterm/addon-web-links": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@xterm/addon-web-links/-/addon-web-links-0.11.0.tgz", + "integrity": "sha512-nIHQ38pQI+a5kXnRaTgwqSHnX7KE6+4SVoceompgHL26unAxdfP6IPqUTSYPQgSwM56hsElfoNrrW5V7BUED/Q==", + "license": "MIT", + "peerDependencies": { + "@xterm/xterm": "^5.0.0" + } }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true, - "license": "Apache-2.0" + "node_modules/@xterm/addon-webgl": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@xterm/addon-webgl/-/addon-webgl-0.18.0.tgz", + "integrity": "sha512-xCnfMBTI+/HKPdRnSOHaJDRqEpq2Ugy8LEj9GiY4J3zJObo3joylIFaMvzBwbYRg8zLtkO0KQaStCeSfoaI2/w==", + "license": "MIT", + "peerDependencies": { + "@xterm/xterm": "^5.0.0" + } }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true, + "node_modules/@xterm/xterm": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz", + "integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==", "license": "MIT" }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, - "license": "MIT" + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } }, - "node_modules/electron-to-chromium": { - "version": "1.5.250", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.250.tgz", - "integrity": "sha512-/5UMj9IiGDMOFBnN4i7/Ry5onJrAGSbOGo3s9FEKmwobGq6xw832ccET0CE3CkkMBZ8GJSlUIesZofpyurqDXw==", + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, - "license": "ISC" + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">= 14" + } }, - "node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, - "hasInstallScript": true, "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, - "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" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=8.6.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "license": "ISC", "dependencies": { - "is-glob": "^4.0.1" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" }, "engines": { - "node": ">= 6" + "node": ">= 8" } }, - "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } + "license": "MIT" }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" + "tslib": "^2.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/font-finder": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/font-finder/-/font-finder-1.1.0.tgz", - "integrity": "sha512-wpCL2uIbi6GurJbU7ZlQ3nGd61Ho+dSU6U83/xJT5UPFfN35EeCW/rOtS+5k+IuEZu2SYmHzDIPL9eA5tSYRAw==", - "license": "MIT", + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "get-system-fonts": "^2.0.0", - "promise-stream-reader": "^1.0.1" - }, - "engines": { - "node": ">8.0.0" + "dequal": "^2.0.3" } }, - "node_modules/font-ligatures": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/font-ligatures/-/font-ligatures-1.4.1.tgz", - "integrity": "sha512-7W6zlfyhvCqShZ5ReUWqmSd9vBaUudW0Hxis+tqUjtHhsPU+L3Grf8mcZAtCiXHTzorhwdRTId2WeH/88gdFkw==", + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, "license": "MIT", "dependencies": { - "font-finder": "^1.0.3", - "lru-cache": "^6.0.0", - "opentype.js": "^0.8.0" + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" }, "engines": { - "node": ">8.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/font-ligatures/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "license": "ISC", + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" }, "engines": { - "node": ">=10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/font-ligatures/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" }, "engines": { - "node": ">=14" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fraction.js": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", - "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", "dev": true, "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, "engines": { - "node": "*" + "node": ">= 0.4" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/rawify" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", "dev": true, - "hasInstallScript": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", "dev": true, "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-nonce": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", - "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/get-system-fonts": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-system-fonts/-/get-system-fonts-2.0.2.tgz", - "integrity": "sha512-zzlgaYnHMIEgHRrfC7x0Qp0Ylhw/sHpM6MHXeVBTYIsvGf5GpbnClB+Q6rAPdn+0gd2oZZIo6Tj3EaWrt4VhDQ==", - "license": "MIT", - "engines": { - "node": ">8.0.0" + "node": ">= 0.4" } }, - "node_modules/ghostty-web": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/ghostty-web/-/ghostty-web-0.3.0.tgz", - "integrity": "sha512-SAdSHWYF20GMZUB0n8kh1N6Z4ljMnuUqT8iTB2n5FAPswEV10MejEpLlhW/769GL5+BQa1NYwEg9y/XCckV5+A==", - "license": "MIT" - }, - "node_modules/glob": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" }, - "bin": { - "glob": "dist/esm/bin.mjs" + "engines": { + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, + "license": "MIT", "engines": { - "node": ">=10.13.0" + "node": ">=12" } }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", "dev": true, "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, "engines": { "node": ">= 0.4" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "node_modules/autoprefixer": { + "version": "10.4.23", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.23.tgz", + "integrity": "sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { - "binary-extensions": "^2.0.0" + "browserslist": "^4.28.1", + "caniuse-lite": "^1.0.30001760", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" }, "engines": { - "node": ">=8" + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, "license": "MIT", "dependencies": { - "hasown": "^2.0.2" + "possible-typed-array-names": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -3157,181 +3893,3605 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", "license": "MIT", - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.7", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.7.tgz", + "integrity": "sha512-k9xFKplee6KIio3IDbwj+uaCLpqzOwakOgmqzPezM0sFJlFKcg30vk2wOiAJtkTSfx0SSQDSe8q+mWA/fSH5Zg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/bidi-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", "dev": true, "license": "MIT", "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" + "require-from-string": "^2.0.2" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.12.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, - "license": "ISC" + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "fill-range": "^7.1.1" }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" + "engines": { + "node": ">=8" } }, - "node_modules/jiti": { - "version": "1.21.7", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", - "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, "bin": { - "jiti": "bin/jiti.js" + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/js-base64": { - "version": "3.7.8", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.8.tgz", - "integrity": "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==", - "license": "BSD-3-Clause" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", "dev": true, "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" }, "engines": { - "node": ">=6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, "license": "MIT", - "bin": { - "json5": "lib/cli.js" + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" }, "engines": { - "node": ">=6" + "node": ">= 0.4" } }, - "node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "dev": true, "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, "engines": { - "node": ">=14" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/antonk52" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=6" + } }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001760", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001760.tgz", + "integrity": "sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chai": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.1.tgz", + "integrity": "sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, "license": "MIT", "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, - "bin": { - "loose-envify": "cli.js" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "yallist": "^3.0.2" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "node_modules/lucide-react": { - "version": "0.294.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.294.0.tgz", - "integrity": "sha512-V7o0/VECSGbLHn3/1O67FUgBwWB+hmzshrgDVRJQhMh8uj5D3HBuIvhuAmQTtlupILSplwIZg5FTc4tTKMA2SA==", + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cmdk": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.1.1.tgz", + "integrity": "sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "^1.1.1", + "@radix-ui/react-dialog": "^1.1.6", + "@radix-ui/react-id": "^1.1.0", + "@radix-ui/react-primitive": "^2.0.2" + }, "peerDependencies": { - "react": "^16.5.1 || ^17.0.0 || ^18.0.0" + "react": "^18 || ^19 || ^19.0.0-rc", + "react-dom": "^18 || ^19 || ^19.0.0-rc" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-tree": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", + "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.12.2", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-tree/node_modules/mdn-data": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", + "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssstyle": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.4.tgz", + "integrity": "sha512-KyOS/kJMEq5O9GdPnaf82noigg5X5DYn0kZPJTaAsCUaBizp6Xa1y9D4Qoqf/JazEXWuruErHgVXwjN5391ZJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^4.1.0", + "@csstools/css-syntax-patches-for-csstree": "1.0.14", + "css-tree": "^3.1.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/data-urls": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-6.0.0.tgz", + "integrity": "sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^15.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/decode-named-character-reference": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz", + "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true, + "license": "MIT" + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.267", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", + "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", + "dev": true, + "license": "ISC" + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-abstract": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", + "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.2.tgz", + "integrity": "sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.1", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.1.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.3.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.5", + "safe-array-concat": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "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" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.2", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.37.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.9", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fault": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", + "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/font-finder": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/font-finder/-/font-finder-1.1.0.tgz", + "integrity": "sha512-wpCL2uIbi6GurJbU7ZlQ3nGd61Ho+dSU6U83/xJT5UPFfN35EeCW/rOtS+5k+IuEZu2SYmHzDIPL9eA5tSYRAw==", + "license": "MIT", + "dependencies": { + "get-system-fonts": "^2.0.0", + "promise-stream-reader": "^1.0.1" + }, + "engines": { + "node": ">8.0.0" + } + }, + "node_modules/font-ligatures": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/font-ligatures/-/font-ligatures-1.4.1.tgz", + "integrity": "sha512-7W6zlfyhvCqShZ5ReUWqmSd9vBaUudW0Hxis+tqUjtHhsPU+L3Grf8mcZAtCiXHTzorhwdRTId2WeH/88gdFkw==", + "license": "MIT", + "dependencies": { + "font-finder": "^1.0.3", + "lru-cache": "^6.0.0", + "opentype.js": "^0.8.0" + }, + "engines": { + "node": ">8.0.0" + } + }, + "node_modules/font-ligatures/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/font-ligatures/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-system-fonts": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-system-fonts/-/get-system-fonts-2.0.2.tgz", + "integrity": "sha512-zzlgaYnHMIEgHRrfC7x0Qp0Ylhw/sHpM6MHXeVBTYIsvGf5GpbnClB+Q6rAPdn+0gd2oZZIo6Tj3EaWrt4VhDQ==", + "license": "MIT", + "engines": { + "node": ">8.0.0" + } + }, + "node_modules/github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", + "dev": true, + "license": "ISC" + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", + "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/html-url-attributes": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", + "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inline-style-parser": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", + "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", + "license": "MIT" + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-base64": { + "version": "3.7.8", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.8.tgz", + "integrity": "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==", + "license": "BSD-3-Clause" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.3.0.tgz", + "integrity": "sha512-GtldT42B8+jefDUC4yUKAvsaOrH7PDHmZxZXNgF2xMmymjUbRYJvpAybZAKEmXDGTM0mCsz8duOa4vTm5AY2Kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@acemir/cssom": "^0.9.28", + "@asamuzakjp/dom-selector": "^6.7.6", + "cssstyle": "^5.3.4", + "data-urls": "^6.0.0", + "decimal.js": "^10.6.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "is-potential-custom-element-name": "^1.0.1", + "parse5": "^8.0.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^6.0.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^8.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^15.1.0", + "ws": "^8.18.3", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.294.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.294.0.tgz", + "integrity": "sha512-V7o0/VECSGbLHn3/1O67FUgBwWB+hmzshrgDVRJQhMh8uj5D3HBuIvhuAmQTtlupILSplwIZg5FTc4tTKMA2SA==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", + "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-frontmatter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz", + "integrity": "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "escape-string-regexp": "^5.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-frontmatter/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdn-data": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.23.0.tgz", + "integrity": "sha512-786vq1+4079JSeu2XdcDjrhi/Ry7BWtjDl9WtGPWLiIHb2T66GvIVflZTBoSNZ5JqTtJGYEVMuFA/lbQlMOyDQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-frontmatter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz", + "integrity": "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fault": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">= 8" + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -3346,30 +7506,27 @@ "node": ">=8.6" } }, - "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, + "license": "MIT", "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=4" } }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "*" } }, "node_modules/monaco-editor": { @@ -3382,7 +7539,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/mz": { @@ -3416,6 +7572,13 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, "node_modules/node-releases": { "version": "2.0.27", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", @@ -3433,16 +7596,6 @@ "node": ">=0.10.0" } }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -3463,6 +7616,115 @@ "node": ">= 6" } }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, "node_modules/opentype.js": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/opentype.js/-/opentype.js-0.8.0.tgz", @@ -3475,12 +7737,169 @@ "ot": "bin/ot" } }, - "node_modules/package-json-from-dist": { + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/oxlint": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/oxlint/-/oxlint-1.33.0.tgz", + "integrity": "sha512-4WCL0K8jiOshwJ8WrVk35VAuVaZHC0iX6asjKsrENOrynkAAGcTLLx0Urf0eXZ1Tq7r+qAe3Z9EyHMFPzVyUkg==", + "dev": true, + "license": "MIT", + "bin": { + "oxc_language_server": "bin/oxc_language_server", + "oxlint": "bin/oxlint" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxlint/darwin-arm64": "1.33.0", + "@oxlint/darwin-x64": "1.33.0", + "@oxlint/linux-arm64-gnu": "1.33.0", + "@oxlint/linux-arm64-musl": "1.33.0", + "@oxlint/linux-x64-gnu": "1.33.0", + "@oxlint/linux-x64-musl": "1.33.0", + "@oxlint/win32-arm64": "1.33.0", + "@oxlint/win32-x64": "1.33.0" + }, + "peerDependencies": { + "oxlint-tsgolint": ">=0.9.0" + }, + "peerDependenciesMeta": { + "oxlint-tsgolint": { + "optional": true + } + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/parse5": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", + "integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==", "dev": true, - "license": "BlueOak-1.0.0" + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } }, "node_modules/path-key": { "version": "3.1.1", @@ -3499,29 +7918,12 @@ "dev": true, "license": "MIT" }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true, - "license": "ISC" + "license": "MIT" }, "node_modules/picocolors": { "version": "1.1.1", @@ -3563,6 +7965,16 @@ "node": ">= 6" } }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", @@ -3610,6 +8022,27 @@ "postcss": "^8.0.0" } }, + "node_modules/postcss-import/node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/postcss-js": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", @@ -3705,7 +8138,7 @@ "postcss": "^8.2.14" } }, - "node_modules/postcss-selector-parser": { + "node_modules/postcss-nested/node_modules/postcss-selector-parser": { "version": "6.1.2", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", @@ -3719,6 +8152,20 @@ "node": ">=4" } }, + "node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/postcss-value-parser": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", @@ -3726,6 +8173,50 @@ "dev": true, "license": "MIT" }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prism-themes": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/prism-themes/-/prism-themes-1.9.0.tgz", + "integrity": "sha512-tX2AYsehKDw1EORwBps+WhBFKc2kxfoFpQAjxBndbZKr4fRmMkv47XN0BghC/K1qwodB1otbe4oF23vUTFDokw==", + "license": "MIT" + }, "node_modules/prismjs": { "version": "1.30.0", "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", @@ -3744,6 +8235,45 @@ "node": ">8.0.0" } }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -3790,6 +8320,40 @@ "react": "^18.3.1" } }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-markdown": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz", + "integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==", + "license": "MIT", + "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" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=18", + "react": ">=18" + } + }, "node_modules/react-refresh": { "version": "0.17.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", @@ -3801,9 +8365,9 @@ } }, "node_modules/react-remove-scroll": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz", - "integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", "license": "MIT", "dependencies": { "react-remove-scroll-bar": "^2.3.7", @@ -3902,27 +8466,168 @@ "node": ">=8.10.0" } }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", "dev": true, "license": "MIT", "dependencies": { - "is-core-module": "^2.16.1", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, - "engines": { - "node": ">= 0.4" - }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -3935,9 +8640,9 @@ } }, "node_modules/rollup": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.2.tgz", - "integrity": "sha512-MHngMYwGJVi6Fmnk6ISmnk7JAHRNF0UkuucA0CUW3N3a4KnONPEZz+vUanQP/ZC/iY1Qkf3bwPWzyY84wEks1g==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.5.tgz", + "integrity": "sha512-iTNAbFSlRpcHeeWu73ywU/8KuU/LZmNCSxp6fjQkJBD3ivUb8tpDrXhIxEzA05HlYMEwmtaUnb3RP+YNv162OQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3951,28 +8656,28 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.53.2", - "@rollup/rollup-android-arm64": "4.53.2", - "@rollup/rollup-darwin-arm64": "4.53.2", - "@rollup/rollup-darwin-x64": "4.53.2", - "@rollup/rollup-freebsd-arm64": "4.53.2", - "@rollup/rollup-freebsd-x64": "4.53.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.53.2", - "@rollup/rollup-linux-arm-musleabihf": "4.53.2", - "@rollup/rollup-linux-arm64-gnu": "4.53.2", - "@rollup/rollup-linux-arm64-musl": "4.53.2", - "@rollup/rollup-linux-loong64-gnu": "4.53.2", - "@rollup/rollup-linux-ppc64-gnu": "4.53.2", - "@rollup/rollup-linux-riscv64-gnu": "4.53.2", - "@rollup/rollup-linux-riscv64-musl": "4.53.2", - "@rollup/rollup-linux-s390x-gnu": "4.53.2", - "@rollup/rollup-linux-x64-gnu": "4.53.2", - "@rollup/rollup-linux-x64-musl": "4.53.2", - "@rollup/rollup-openharmony-arm64": "4.53.2", - "@rollup/rollup-win32-arm64-msvc": "4.53.2", - "@rollup/rollup-win32-ia32-msvc": "4.53.2", - "@rollup/rollup-win32-x64-gnu": "4.53.2", - "@rollup/rollup-win32-x64-msvc": "4.53.2", + "@rollup/rollup-android-arm-eabi": "4.53.5", + "@rollup/rollup-android-arm64": "4.53.5", + "@rollup/rollup-darwin-arm64": "4.53.5", + "@rollup/rollup-darwin-x64": "4.53.5", + "@rollup/rollup-freebsd-arm64": "4.53.5", + "@rollup/rollup-freebsd-x64": "4.53.5", + "@rollup/rollup-linux-arm-gnueabihf": "4.53.5", + "@rollup/rollup-linux-arm-musleabihf": "4.53.5", + "@rollup/rollup-linux-arm64-gnu": "4.53.5", + "@rollup/rollup-linux-arm64-musl": "4.53.5", + "@rollup/rollup-linux-loong64-gnu": "4.53.5", + "@rollup/rollup-linux-ppc64-gnu": "4.53.5", + "@rollup/rollup-linux-riscv64-gnu": "4.53.5", + "@rollup/rollup-linux-riscv64-musl": "4.53.5", + "@rollup/rollup-linux-s390x-gnu": "4.53.5", + "@rollup/rollup-linux-x64-gnu": "4.53.5", + "@rollup/rollup-linux-x64-musl": "4.53.5", + "@rollup/rollup-openharmony-arm64": "4.53.5", + "@rollup/rollup-win32-arm64-msvc": "4.53.5", + "@rollup/rollup-win32-ia32-msvc": "4.53.5", + "@rollup/rollup-win32-x64-gnu": "4.53.5", + "@rollup/rollup-win32-x64-msvc": "4.53.5", "fsevents": "~2.3.2" } }, @@ -4000,6 +8705,81 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, "node_modules/scheduler": { "version": "0.23.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", @@ -4019,6 +8799,55 @@ "semver": "bin/semver.js" } }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -4026,35 +8855,105 @@ "dev": true, "license": "MIT", "dependencies": { - "shebang-regex": "^3.0.0" + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "dev": true, - "license": "ISC", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, "engines": { - "node": ">=14" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -4065,129 +8964,219 @@ "node": ">=0.10.0" } }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, "node_modules/state-local": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz", "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==", "license": "MIT" }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", "dev": true, "license": "MIT", "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.4" } }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", "dev": true, "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/string-width-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" } }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/string-width-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^6.0.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">=12" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "min-indent": "^1.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, "license": "MIT", "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-to-js": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", + "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.14" + } + }, + "node_modules/style-to-object": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", + "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.7" } }, "node_modules/sucrase": { - "version": "3.35.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", - "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", - "glob": "^10.3.10", "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": { @@ -4198,6 +9187,19 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -4211,6 +9213,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, "node_modules/tailwind-merge": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.0.tgz", @@ -4222,9 +9231,9 @@ } }, "node_modules/tailwindcss": { - "version": "3.4.18", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.18.tgz", - "integrity": "sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==", + "version": "3.4.19", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4259,6 +9268,41 @@ "node": ">=14.0.0" } }, + "node_modules/tailwindcss/node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tailwindcss/node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -4288,6 +9332,23 @@ "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", "license": "MIT" }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -4336,6 +9397,36 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/tinyrainbow": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", + "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "7.0.19", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.19.tgz", + "integrity": "sha512-8PWx8tvC4jDB39BQw1m4x8y5MH1BcQ5xHeL2n7UVFulMPH/3Q0uiamahFJ3lXA0zO2SUyRXuVVbWSDmstlt9YA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^7.0.19" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "7.0.19", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.19.tgz", + "integrity": "sha512-lJX2dEWx0SGH4O6p+7FPwYmJ/bu1JbcGJ8RLaG9b7liIgZ85itUVEPbMtWRVrde/0fnDPEPHW10ZsKW3kVsE9A==", + "dev": true, + "license": "MIT" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -4349,6 +9440,65 @@ "node": ">=8.0" } }, + "node_modules/tough-cookie": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.0.tgz", + "integrity": "sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", + "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", @@ -4362,6 +9512,97 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/typescript": { "version": "5.6.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", @@ -4376,6 +9617,49 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "8.50.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.50.0.tgz", + "integrity": "sha512-Q1/6yNUmCpH94fbgMUMg2/BSAr/6U7GBk61kZTv1/asghQOWOjTlp9K8mixS5NcJmm2creY+UFfGeW/+OcA64A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.50.0", + "@typescript-eslint/parser": "8.50.0", + "@typescript-eslint/typescript-estree": "8.50.0", + "@typescript-eslint/utils": "8.50.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/undici-types": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", @@ -4383,10 +9667,97 @@ "dev": true, "license": "MIT" }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/update-browserslist-db": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", - "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.2.tgz", + "integrity": "sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==", "dev": true, "funding": [ { @@ -4414,6 +9785,16 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/use-callback-ref": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", @@ -4477,6 +9858,34 @@ "uuid": "dist-node/bin/uuid" } }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/vite": { "version": "6.4.1", "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", @@ -4593,6 +10002,157 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/vitest": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.15.tgz", + "integrity": "sha512-n1RxDp8UJm6N0IbJLQo+yzLZ2sQCDyl1o0LeugbPWf8+8Fttp29GghsQBjYJVmWq3gBFfe9Hs1spR44vovn2wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.0.15", + "@vitest/mocker": "4.0.15", + "@vitest/pretty-format": "4.0.15", + "@vitest/runner": "4.0.15", + "@vitest/snapshot": "4.0.15", + "@vitest/spy": "4.0.15", + "@vitest/utils": "4.0.15", + "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" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "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.15", + "@vitest/browser-preview": "4.0.15", + "@vitest/browser-webdriverio": "4.0.15", + "@vitest/ui": "4.0.15", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.0.tgz", + "integrity": "sha512-n4W4YFyz5JzOfQeA8oN7dUYpR+MBP3PIUsn2jLjWXwK5ASUzt0Jc/A5sAUZoCYFJRGF0FBKJ+1JjN43rNdsQzA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-15.1.0.tgz", + "integrity": "sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.0" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -4609,110 +10169,190 @@ "node": ">= 8" } }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" }, "engines": { - "node": ">=12" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "dev": true, "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", "dev": true, "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" }, "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" }, "engines": { "node": ">=8" } }, - "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=8" + "node": ">=18" } }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true, "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } } } } diff --git a/package.json b/package.json index 22429c5d..8cb135ad 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,12 @@ "build": "tsc && vite build", "preview": "vite preview", "tauri": "tauri", - "clean": "cd src-tauri && cargo clean" + "clean": "cd src-tauri && cargo clean", + "test": "vitest", + "test:run": "vitest run", + "test:ui": "vitest --ui", + "check": "tsc", + "lint": "oxlint && eslint ." }, "dependencies": { "@monaco-editor/react": "^4.6.0", @@ -32,25 +37,42 @@ "cmdk": "^1.1.1", "lucide-react": "^0.294.0", "monaco-editor": "^0.45.0", + "prism-themes": "^1.9.0", "prismjs": "^1.30.0", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-markdown": "^10.1.0", "react-window": "^2.2.3", + "remark-gfm": "^4.0.1", "tailwind-merge": "^2.1.0", "uuid": "^13.0.0" }, "devDependencies": { + "@eslint/css": "^0.14.1", + "@eslint/js": "^9.39.2", + "@eslint/markdown": "^7.5.1", + "@tailwindcss/typography": "^0.5.19", "@tauri-apps/cli": "^2", + "@testing-library/dom": "^10.4.1", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.1", "@types/node": "^20.10.5", "@types/prismjs": "^1.26.5", - "@types/react": "^18.3.1", - "@types/react-dom": "^18.3.1", + "@types/react": "^18.3.27", + "@types/react-dom": "^18.3.7", "@vitejs/plugin-react": "^4.3.4", "autoprefixer": "^10.4.16", + "eslint": "^9.39.2", + "eslint-plugin-react": "^7.37.5", + "globals": "^16.5.0", + "jsdom": "^27.3.0", + "oxlint": "^1.33.0", "postcss": "^8.4.32", "tailwindcss": "^3.3.6", "typescript": "~5.6.2", + "typescript-eslint": "^8.50.0", "vite": "^6.0.3", - "vite-plugin-monaco-editor": "^1.1.0" + "vite-plugin-monaco-editor": "^1.1.0", + "vitest": "^4.0.15" } } diff --git a/public/prism-themes/themes/prism-vs.css b/public/prism-themes/themes/prism-vs.css new file mode 100644 index 00000000..54377dfa --- /dev/null +++ b/public/prism-themes/themes/prism-vs.css @@ -0,0 +1,168 @@ +/** + * VS theme by Andrew Lock (https://andrewlock.net) + * Inspired by Visual Studio syntax coloring + */ + +code[class*="language-"], +pre[class*="language-"] { + color: #393A34; + font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace; + direction: ltr; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + font-size: .9em; + line-height: 1.2em; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +pre > code[class*="language-"] { + font-size: 1em; +} + +pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, +code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { + background: #C1DEF1; +} + +pre[class*="language-"]::selection, pre[class*="language-"] ::selection, +code[class*="language-"]::selection, code[class*="language-"] ::selection { + background: #C1DEF1; +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: .5em 0; + overflow: auto; + border: 1px solid #dddddd; + background-color: white; +} + +/* Inline code */ +:not(pre) > code[class*="language-"] { + padding: .2em; + padding-top: 1px; + padding-bottom: 1px; + background: #f8f8f8; + border: 1px solid #dddddd; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: #008000; + font-style: italic; +} + +.token.namespace { + opacity: .7; +} + +.token.string { + color: #A31515; +} + +.token.punctuation, +.token.operator { + color: #393A34; /* no highlight */ +} + +.token.url, +.token.symbol, +.token.number, +.token.boolean, +.token.variable, +.token.constant, +.token.inserted { + color: #36acaa; +} + +.token.atrule, +.token.keyword, +.token.attr-value, +.language-autohotkey .token.selector, +.language-json .token.boolean, +.language-json .token.number, +code[class*="language-css"] { + color: #0000ff; +} + +.token.function { + color: #393A34; +} + +.token.deleted, +.language-autohotkey .token.tag { + color: #9a050f; +} + +.token.selector, +.language-autohotkey .token.keyword { + color: #00009f; +} + +.token.important { + color: #e90; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic { + font-style: italic; +} + +.token.class-name, +.language-json .token.property { + color: #2B91AF; +} + +.token.tag, +.token.selector { + color: #800000; +} + +.token.attr-name, +.token.property, +.token.regex, +.token.entity { + color: #ff0000; +} + +.token.directive.tag .tag { + background: #ffff00; + color: #393A34; +} + +/* overrides color-values for the Line Numbers plugin + * http://prismjs.com/plugins/line-numbers/ + */ +.line-numbers.line-numbers .line-numbers-rows { + border-right-color: #a5a5a5; +} + +.line-numbers .line-numbers-rows > span:before { + color: #2B91AF; +} + +/* overrides color-values for the Line Highlight plugin +* http://prismjs.com/plugins/line-highlight/ +*/ +.line-highlight.line-highlight { + background: rgba(193, 222, 241, 0.2); + background: -webkit-linear-gradient(left, rgba(193, 222, 241, 0.2) 70%, rgba(221, 222, 241, 0)); + background: linear-gradient(to right, rgba(193, 222, 241, 0.2) 70%, rgba(221, 222, 241, 0)); +} diff --git a/public/prism-themes/themes/prism-vsc-dark-plus.css b/public/prism-themes/themes/prism-vsc-dark-plus.css new file mode 100644 index 00000000..d3bd5010 --- /dev/null +++ b/public/prism-themes/themes/prism-vsc-dark-plus.css @@ -0,0 +1,275 @@ +pre[class*="language-"], +code[class*="language-"] { + color: #d4d4d4; + font-size: 13px; + text-shadow: none; + font-family: Menlo, Monaco, Consolas, "Andale Mono", "Ubuntu Mono", "Courier New", monospace; + direction: ltr; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + line-height: 1.5; + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +pre[class*="language-"]::selection, +code[class*="language-"]::selection, +pre[class*="language-"] *::selection, +code[class*="language-"] *::selection { + text-shadow: none; + background: #264F78; +} + +@media print { + pre[class*="language-"], + code[class*="language-"] { + text-shadow: none; + } +} + +pre[class*="language-"] { + padding: 1em; + margin: .5em 0; + overflow: auto; + background: #1e1e1e; +} + +:not(pre) > code[class*="language-"] { + padding: .1em .3em; + border-radius: .3em; + color: #db4c69; + background: #1e1e1e; +} +/********************************************************* +* Tokens +*/ +.namespace { + opacity: .7; +} + +.token.doctype .token.doctype-tag { + color: #569CD6; +} + +.token.doctype .token.name { + color: #9cdcfe; +} + +.token.comment, +.token.prolog { + color: #6a9955; +} + +.token.punctuation, +.language-html .language-css .token.punctuation, +.language-html .language-javascript .token.punctuation { + color: #d4d4d4; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.inserted, +.token.unit { + color: #b5cea8; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.deleted { + color: #ce9178; +} + +.language-css .token.string.url { + text-decoration: underline; +} + +.token.operator, +.token.entity { + color: #d4d4d4; +} + +.token.operator.arrow { + color: #569CD6; +} + +.token.atrule { + color: #ce9178; +} + +.token.atrule .token.rule { + color: #c586c0; +} + +.token.atrule .token.url { + color: #9cdcfe; +} + +.token.atrule .token.url .token.function { + color: #dcdcaa; +} + +.token.atrule .token.url .token.punctuation { + color: #d4d4d4; +} + +.token.keyword { + color: #569CD6; +} + +.token.keyword.module, +.token.keyword.control-flow { + color: #c586c0; +} + +.token.function, +.token.function .token.maybe-class-name { + color: #dcdcaa; +} + +.token.regex { + color: #d16969; +} + +.token.important { + color: #569cd6; +} + +.token.italic { + font-style: italic; +} + +.token.constant { + color: #9cdcfe; +} + +.token.class-name, +.token.maybe-class-name { + color: #4ec9b0; +} + +.token.console { + color: #9cdcfe; +} + +.token.parameter { + color: #9cdcfe; +} + +.token.interpolation { + color: #9cdcfe; +} + +.token.punctuation.interpolation-punctuation { + color: #569cd6; +} + +.token.boolean { + color: #569cd6; +} + +.token.property, +.token.variable, +.token.imports .token.maybe-class-name, +.token.exports .token.maybe-class-name { + color: #9cdcfe; +} + +.token.selector { + color: #d7ba7d; +} + +.token.escape { + color: #d7ba7d; +} + +.token.tag { + color: #569cd6; +} + +.token.tag .token.punctuation { + color: #808080; +} + +.token.cdata { + color: #808080; +} + +.token.attr-name { + color: #9cdcfe; +} + +.token.attr-value, +.token.attr-value .token.punctuation { + color: #ce9178; +} + +.token.attr-value .token.punctuation.attr-equals { + color: #d4d4d4; +} + +.token.entity { + color: #569cd6; +} + +.token.namespace { + color: #4ec9b0; +} +/********************************************************* +* Language Specific +*/ + +pre[class*="language-javascript"], +code[class*="language-javascript"], +pre[class*="language-jsx"], +code[class*="language-jsx"], +pre[class*="language-typescript"], +code[class*="language-typescript"], +pre[class*="language-tsx"], +code[class*="language-tsx"] { + color: #9cdcfe; +} + +pre[class*="language-css"], +code[class*="language-css"] { + color: #ce9178; +} + +pre[class*="language-html"], +code[class*="language-html"] { + color: #d4d4d4; +} + +.language-regex .token.anchor { + color: #dcdcaa; +} + +.language-html .token.punctuation { + color: #808080; +} +/********************************************************* +* Line highlighting +*/ +pre[class*="language-"] > code[class*="language-"] { + position: relative; + z-index: 1; +} + +.line-highlight.line-highlight { + background: #f7ebc6; + box-shadow: inset 5px 0 0 #f7d87c; + z-index: 0; +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml deleted file mode 100644 index 5d56faf9..00000000 --- a/rust-toolchain.toml +++ /dev/null @@ -1,2 +0,0 @@ -[toolchain] -channel = "nightly" diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 7d6707f3..8f93bf78 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1081,6 +1081,15 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "file-id" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1fc6a637b6dc58414714eddd9170ff187ecb0933d4c7024d1abbd23a3cc26e9" +dependencies = [ + "windows-sys 0.60.2", +] + [[package]] name = "filedescriptor" version = "0.8.3" @@ -1174,6 +1183,15 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fsevent-sys" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] + [[package]] name = "futf" version = "0.1.5" @@ -2683,6 +2701,26 @@ dependencies = [ "cfb", ] +[[package]] +name = "inotify" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" +dependencies = [ + "bitflags 1.3.2", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + [[package]] name = "interim" version = "0.2.1" @@ -2950,6 +2988,26 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "kqueue" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + [[package]] name = "kstring" version = "2.0.2" @@ -3252,6 +3310,18 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "log", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.48.0", +] + [[package]] name = "mio" version = "1.1.0" @@ -3353,6 +3423,39 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" +[[package]] +name = "notify" +version = "6.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" +dependencies = [ + "bitflags 2.10.0", + "crossbeam-channel", + "filetime", + "fsevent-sys", + "inotify", + "kqueue", + "libc", + "log", + "mio 0.8.11", + "walkdir", + "windows-sys 0.48.0", +] + +[[package]] +name = "notify-debouncer-full" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb7fd166739789c9ff169e654dc1501373db9d80a4c3f972817c8a4d7cf8f34e" +dependencies = [ + "crossbeam-channel", + "file-id", + "log", + "notify", + "parking_lot", + "walkdir", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -5605,7 +5708,7 @@ checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ "bytes", "libc", - "mio", + "mio 1.1.0", "pin-project-lite", "signal-hook-registry", "socket2", @@ -5840,11 +5943,15 @@ name = "treq" version = "0.1.0" dependencies = [ "chrono", + "crossbeam-channel", "git2", "globset", "ignore", "jj-lib", + "notify", + "notify-debouncer-full", "portable-pty", + "rayon", "rusqlite", "serde", "serde_json", @@ -6510,6 +6617,15 @@ dependencies = [ "windows-targets 0.42.2", ] +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.59.0" @@ -6552,6 +6668,21 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -6609,6 +6740,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -6627,6 +6764,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -6645,6 +6788,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -6675,6 +6824,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -6693,6 +6848,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -6711,6 +6872,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -6729,6 +6896,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 8b322a9c..14ba6020 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -34,6 +34,10 @@ walkdir = "2" globset = "0.4" git2 = { version = "0.20.2", features = ["https", "ssh"] } jj-lib = "0.36.0" +notify = { version = "6.1", default-features = false, features = ["macos_fsevent"] } +notify-debouncer-full = "0.3" +crossbeam-channel = "0.5" +rayon = "1.10" # ============================================================================= # Profile Configuration diff --git a/src-tauri/rustc-ice-2025-12-16T15_26_09-81268.txt b/src-tauri/rustc-ice-2025-12-16T15_26_09-81268.txt new file mode 100644 index 00000000..9352a227 --- /dev/null +++ b/src-tauri/rustc-ice-2025-12-16T15_26_09-81268.txt @@ -0,0 +1,27 @@ +thread 'rustc' panicked at compiler/rustc_codegen_ssa/src/back/link.rs:508:14: +called `Result::unwrap()` on an `Err` value: Os { code: 2, kind: NotFound, message: "No such file or directory" } +stack backtrace: + 0: 0x1109de754 - std::backtrace::Backtrace::create::h02af77af33ea387a + 1: 0x10ea2343c - std[4e66f15f83134380]::panicking::update_hook::>::{closure#0} + 2: 0x1109df61c - std::panicking::panic_with_hook::h108cad016a81b514 + 3: 0x1109df298 - std::panicking::panic_handler::{{closure}}::h3d2375b8dd9fb867 + 4: 0x1109d8ce4 - std::sys::backtrace::__rust_end_short_backtrace::h229f370ba79d9191 + 5: 0x1109bd8b4 - __rustc[c381d3d25b5a82e6]::rust_begin_unwind + 6: 0x113745190 - core::panicking::panic_fmt::h81f14fbe760c42ef + 7: 0x113744c18 - core::result::unwrap_failed::h72558f11a1c986ee + 8: 0x10e7dcb10 - rustc_codegen_ssa[eaf0851a9d0fd52a]::back::link::link_staticlib::{closure#0} + 9: 0x10e825e08 - rustc_codegen_ssa[eaf0851a9d0fd52a]::back::link::each_linked_rlib + 10: 0x10e813c18 - rustc_codegen_ssa[eaf0851a9d0fd52a]::back::link::link_binary + 11: 0x10f2e6974 - ::link + 12: 0x10ea21978 - rustc_interface[d6f679bb5cbe7b6]::interface::run_compiler::<(), rustc_driver_impl[1c081e8c11b34763]::run_compiler::{closure#0}>::{closure#1} + 13: 0x10ea59da0 - , ::in_worker_cold<::install::{closure#1}, ()>::{closure#5}::{closure#0}::{closure#1}::{closure#0}, ()>::{closure#0}, ()>::{closure#0}::{closure#0}, ()> as rustc_thread_pool[ebed644b9395ad33]::job::Job>::execute + 14: 0x1138cdfb8 - ::wait_or_steal_until_cold + 15: 0x110540d5c - ::run + 16: 0x10ea14b6c - std[4e66f15f83134380]::sys::backtrace::__rust_begin_short_backtrace::<::build_scoped::{closure#1}, ()>::{closure#5}::{closure#0}::{closure#0}, rustc_interface[d6f679bb5cbe7b6]::util::run_in_thread_pool_with_globals::{closure#1}, ()>::{closure#5}::{closure#0}::{closure#1}, ()>::{closure#0}::{closure#0}::{closure#0}, ()> + 17: 0x10ea28684 - <::spawn_unchecked_<::build_scoped::{closure#1}, ()>::{closure#5}::{closure#0}::{closure#0}, rustc_interface[d6f679bb5cbe7b6]::util::run_in_thread_pool_with_globals::{closure#1}, ()>::{closure#5}::{closure#0}::{closure#1}, ()>::{closure#0}::{closure#0}::{closure#0}, ()>::{closure#1} as core[9ef14882c924e924]::ops::function::FnOnce<()>>::call_once::{shim:vtable#0} + 18: 0x1109d5984 - std::sys::thread::unix::Thread::new::thread_start::h02f3d5b58a3773e4 + 19: 0x19bdafc0c - __pthread_cond_wait + + +rustc version: 1.93.0-nightly (c871d09d1 2025-11-24) +platform: aarch64-apple-darwin \ No newline at end of file diff --git a/src-tauri/src/commands/file_view.rs b/src-tauri/src/commands/file_view.rs new file mode 100644 index 00000000..e346d12d --- /dev/null +++ b/src-tauri/src/commands/file_view.rs @@ -0,0 +1,42 @@ +use tauri::State; +use crate::{AppState, db::FileView}; + +#[tauri::command] +pub fn mark_file_viewed( + state: State, + workspace_path: String, + file_path: String, + content_hash: String, +) -> Result<(), String> { + let db = state.db.lock().unwrap(); + db.mark_file_viewed(&workspace_path, &file_path, &content_hash) + .map_err(|e| e.to_string()) +} + +#[tauri::command] +pub fn unmark_file_viewed( + state: State, + workspace_path: String, + file_path: String, +) -> Result<(), String> { + let db = state.db.lock().unwrap(); + db.unmark_file_viewed(&workspace_path, &file_path) + .map_err(|e| e.to_string()) +} + +#[tauri::command] +pub fn get_viewed_files( + state: State, + workspace_path: String, +) -> Result, String> { + let db = state.db.lock().unwrap(); + db.get_viewed_files(&workspace_path) + .map_err(|e| e.to_string()) +} + +#[tauri::command] +pub fn clear_all_viewed_files(state: State, workspace_path: String) -> Result<(), String> { + let db = state.db.lock().unwrap(); + db.clear_all_viewed_files(&workspace_path) + .map_err(|e| e.to_string()) +} diff --git a/src-tauri/src/commands/filesystem.rs b/src-tauri/src/commands/filesystem.rs new file mode 100644 index 00000000..9d1caf1e --- /dev/null +++ b/src-tauri/src/commands/filesystem.rs @@ -0,0 +1,137 @@ +use crate::local_db; +use ignore::WalkBuilder; + +#[derive(serde::Serialize)] +pub struct DirectoryEntry { + pub name: String, + pub path: String, + pub is_directory: bool, +} + +#[derive(serde::Serialize)] +pub struct CachedDirectoryEntry { + pub name: String, + pub path: String, + pub is_directory: bool, + pub relative_path: String, +} + +#[tauri::command] +pub fn read_file(path: String) -> Result { + std::fs::read_to_string(path).map_err(|e| e.to_string()) +} + +#[tauri::command] +pub fn list_directory(path: String) -> Result, String> { + use std::path::Path; + + let base_path = Path::new(&path); + let mut files = Vec::new(); + + // Use ignore::WalkBuilder to respect .gitignore patterns + let walker = WalkBuilder::new(&path) + .max_depth(Some(1)) // Only immediate children + .hidden(false) // Show hidden files (except those in .gitignore) + .git_ignore(true) // Respect .gitignore patterns + .git_global(true) // Respect global gitignore + .git_exclude(true) // Respect .git/info/exclude + .parents(true) // Check parent directories for ignore files + .build(); + + for entry in walker { + if let Ok(entry) = entry { + let entry_path = entry.path(); + + // Skip the base directory itself + if entry_path == base_path { + continue; + } + + if let Some(name) = entry_path.file_name().and_then(|n| n.to_str()) { + let is_dir = entry_path.is_dir(); + files.push(DirectoryEntry { + name: name.to_string(), + path: entry_path.to_string_lossy().to_string(), + is_directory: is_dir, + }); + } + } + } + + // Sort: directories first, then files + files.sort_by(|a, b| match (a.is_directory, b.is_directory) { + (true, false) => std::cmp::Ordering::Less, + (false, true) => std::cmp::Ordering::Greater, + _ => a.name.cmp(&b.name), + }); + + Ok(files) +} + +#[tauri::command] +pub fn list_directory_cached( + repo_path: String, + workspace_id: Option, + parent_path: String, +) -> Result, String> { + use std::path::Path; + + // Try cache first + if let Ok(cached) = local_db::get_cached_directory_listing(&repo_path, workspace_id, &parent_path) { + if !cached.is_empty() { + // Convert to CachedDirectoryEntry format + let entries: Vec = cached + .into_iter() + .map(|file| { + let name = Path::new(&file.file_path) + .file_name() + .and_then(|n| n.to_str()) + .unwrap_or(&file.relative_path) + .to_string(); + CachedDirectoryEntry { + name, + path: file.file_path, + is_directory: file.is_directory, + relative_path: file.relative_path, + } + }) + .collect(); + return Ok(entries); + } + } + + // Cache miss: fall back to live filesystem + let live_entries = list_directory(parent_path.clone())?; + + // Convert live entries to cached format + let entries: Vec = live_entries + .into_iter() + .map(|entry| { + // Compute relative path + let base = Path::new(&parent_path); + let full_path = Path::new(&entry.path); + let relative = full_path + .strip_prefix(base) + .ok() + .and_then(|p| p.to_str()) + .unwrap_or(&entry.name) + .to_string(); + + CachedDirectoryEntry { + name: entry.name, + path: entry.path, + is_directory: entry.is_directory, + relative_path: relative, + } + }) + .collect(); + + Ok(entries) +} + +#[tauri::command] +pub fn get_change_indicators(_workspace_path: String) -> Result, String> { + // TODO: Implement with jj - for now return empty + // This feature shows change indicators in file browser + Ok(Vec::new()) +} diff --git a/src-tauri/src/commands/git_watcher.rs b/src-tauri/src/commands/git_watcher.rs new file mode 100644 index 00000000..8d303bd8 --- /dev/null +++ b/src-tauri/src/commands/git_watcher.rs @@ -0,0 +1,37 @@ +use tauri::State; +use crate::{AppState, local_db}; + +#[tauri::command] +pub fn start_git_watcher( + state: State, + repo_path: String, +) -> Result<(), String> { + // Get all workspace paths + let workspaces = local_db::get_workspaces(&repo_path)?; + let mut workspace_paths: Vec<(Option, String)> = workspaces + .iter() + .map(|w| (Some(w.id), w.workspace_path.clone())) + .collect(); + + // Add main repo + workspace_paths.push((None, repo_path.clone())); + + state.watcher_manager.start_watching(repo_path, workspace_paths) +} + +#[tauri::command] +pub fn stop_git_watcher( + state: State, + repo_path: String, +) -> Result<(), String> { + state.watcher_manager.stop_watching(&repo_path) +} + +#[tauri::command] +pub fn trigger_workspace_scan( + state: State, + repo_path: String, + workspace_id: Option, +) -> Result<(), String> { + state.watcher_manager.trigger_rescan(&repo_path, workspace_id) +} diff --git a/src-tauri/src/commands/jj_commands.rs b/src-tauri/src/commands/jj_commands.rs new file mode 100644 index 00000000..40bdee30 --- /dev/null +++ b/src-tauri/src/commands/jj_commands.rs @@ -0,0 +1,156 @@ +use crate::jj; +use crate::AppState; +use tauri::{AppHandle, State}; + +// JJ Workspace commands + +#[tauri::command] +pub fn jj_create_workspace( + state: State, + _app: AppHandle, + repo_path: String, + workspace_name: String, + branch: String, + new_branch: bool, + source_branch: Option, +) -> Result { + // Load inclusion patterns from database + let inclusion_patterns = { + let db = state.db.lock().unwrap(); + db.get_repo_setting(&repo_path, "included_copy_files") + .ok() + .flatten() + .map(|patterns_str| { + patterns_str + .lines() + .map(|s| s.trim().to_string()) + .filter(|s| !s.is_empty()) + .collect::>() + }) + }; + + jj::create_workspace( + &repo_path, + &workspace_name, + &branch, + new_branch, + source_branch.as_deref(), + inclusion_patterns, + ) + .map_err(|e| e.to_string()) +} + +#[tauri::command] +pub fn jj_list_workspaces( + _state: State, + _app: AppHandle, + repo_path: String, +) -> Result, String> { + jj::list_workspaces(&repo_path).map_err(|e| e.to_string()) +} + +#[tauri::command] +pub fn jj_remove_workspace(repo_path: String, workspace_path: String) -> Result<(), String> { + jj::remove_workspace(&repo_path, &workspace_path).map_err(|e| e.to_string()) +} + +#[tauri::command] +pub fn jj_get_workspace_info(workspace_path: String) -> Result { + jj::get_workspace_info(&workspace_path).map_err(|e| e.to_string()) +} + +#[tauri::command] +pub fn jj_squash_to_workspace( + source_workspace_path: String, + target_workspace_name: String, + file_paths: Option>, +) -> Result { + jj::squash_to_workspace(&source_workspace_path, &target_workspace_name, file_paths) + .map_err(|e| e.to_string()) +} + +#[tauri::command] +pub fn jj_get_changed_files(workspace_path: String) -> Result, String> { + jj::jj_get_changed_files(&workspace_path).map_err(|e| e.to_string()) +} + +#[tauri::command] +pub fn jj_get_file_hunks( + workspace_path: String, + file_path: String, +) -> Result, String> { + jj::jj_get_file_hunks(&workspace_path, &file_path).map_err(|e| e.to_string()) +} + +#[tauri::command] +pub fn jj_get_file_lines( + workspace_path: String, + file_path: String, + from_parent: bool, + start_line: usize, + end_line: usize, +) -> Result { + jj::jj_get_file_lines(&workspace_path, &file_path, from_parent, start_line, end_line) + .map_err(|e| e.to_string()) +} + +#[tauri::command] +pub fn jj_restore_file(workspace_path: String, file_path: String) -> Result { + jj::jj_restore_file(&workspace_path, &file_path).map_err(|e| e.to_string()) +} + +#[tauri::command] +pub fn jj_restore_all(workspace_path: String) -> Result { + jj::jj_restore_all(&workspace_path).map_err(|e| e.to_string()) +} + +#[tauri::command] +pub fn jj_commit(workspace_path: String, message: String) -> Result { + jj::jj_commit(&workspace_path, &message).map_err(|e| e.to_string()) +} + +/// Check if a path has a jj workspace +#[tauri::command] +pub fn jj_is_workspace(repo_path: String) -> bool { + jj::is_jj_workspace(&repo_path) +} + +/// Manually initialize jj for a repository +#[tauri::command] +pub fn jj_init(state: State, repo_path: String) -> Result { + let db = state.db.lock().unwrap(); + jj::ensure_jj_initialized(&db, &repo_path).map_err(|e| e.to_string()) +} + +/// Rebase workspace onto a target branch +#[tauri::command] +pub fn jj_rebase_onto( + workspace_path: String, + target_branch: String, +) -> Result { + jj::jj_rebase_onto(&workspace_path, &target_branch).map_err(|e| e.to_string()) +} + +/// Get list of conflicted files in workspace +#[tauri::command] +pub fn jj_get_conflicted_files(workspace_path: String) -> Result, String> { + jj::get_conflicted_files(&workspace_path).map_err(|e| e.to_string()) +} + +/// Get the default branch of the repository (main/master) +#[tauri::command] +pub fn jj_get_default_branch(repo_path: String) -> Result { + jj::get_default_branch(&repo_path).map_err(|e| e.to_string()) +} + +/// Push changes to remote using jj git push +#[tauri::command] +pub fn jj_push(workspace_path: String) -> Result { + jj::jj_push(&workspace_path).map_err(|e| e.to_string()) +} + +/// Pull changes from remote using jj git fetch + rebase +#[tauri::command] +pub fn jj_pull(workspace_path: String) -> Result { + jj::jj_pull(&workspace_path).map_err(|e| e.to_string()) +} diff --git a/src-tauri/src/commands/mod.rs b/src-tauri/src/commands/mod.rs new file mode 100644 index 00000000..0bd1a272 --- /dev/null +++ b/src-tauri/src/commands/mod.rs @@ -0,0 +1,17 @@ +// Command modules +pub mod workspace; +pub mod settings; +pub mod jj_commands; +pub mod pty_commands; +pub mod filesystem; +pub mod session; +pub mod file_view; + +// Re-export all commands for convenient access +pub use workspace::*; +pub use settings::*; +pub use jj_commands::*; +pub use pty_commands::*; +pub use filesystem::*; +pub use session::*; +pub use file_view::*; diff --git a/src-tauri/src/commands/pty_commands.rs b/src-tauri/src/commands/pty_commands.rs new file mode 100644 index 00000000..37d11e85 --- /dev/null +++ b/src-tauri/src/commands/pty_commands.rs @@ -0,0 +1,54 @@ +use tauri::{AppHandle, Emitter, State}; +use crate::AppState; + +#[tauri::command] +pub fn pty_create_session( + state: State, + app: AppHandle, + session_id: String, + working_dir: Option, + shell: Option, + initial_command: Option, +) -> Result<(), String> { + let pty_manager = state.pty_manager.lock().unwrap(); + let sid = session_id.clone(); + + pty_manager.create_session( + session_id, + working_dir, + shell, + initial_command, + Box::new(move |data| { + let _ = app.emit(&format!("pty-data-{}", sid), data); + }), + ) +} + +#[tauri::command] +pub fn pty_session_exists(state: State, session_id: String) -> Result { + let pty_manager = state.pty_manager.lock().unwrap(); + Ok(pty_manager.session_exists(&session_id)) +} + +#[tauri::command] +pub fn pty_write(state: State, session_id: String, data: String) -> Result<(), String> { + let pty_manager = state.pty_manager.lock().unwrap(); + pty_manager.write_to_session(&session_id, &data) +} + +#[tauri::command] +pub fn pty_resize( + state: State, + session_id: String, + rows: u16, + cols: u16, +) -> Result<(), String> { + let pty_manager = state.pty_manager.lock().unwrap(); + pty_manager.resize_session(&session_id, rows, cols) +} + +#[tauri::command] +pub fn pty_close(state: State, session_id: String) -> Result<(), String> { + let pty_manager = state.pty_manager.lock().unwrap(); + pty_manager.close_session(&session_id) +} diff --git a/src-tauri/src/commands/session.rs b/src-tauri/src/commands/session.rs new file mode 100644 index 00000000..be0b5175 --- /dev/null +++ b/src-tauri/src/commands/session.rs @@ -0,0 +1,41 @@ +use crate::db::Session; +use crate::local_db; + +#[tauri::command] +pub fn create_session( + repo_path: String, + workspace_id: Option, + name: String, +) -> Result { + local_db::add_session(&repo_path, workspace_id, name) +} + +#[tauri::command] +pub fn get_sessions(repo_path: String) -> Result, String> { + local_db::get_sessions(&repo_path) +} + +#[tauri::command] +pub fn update_session_access(repo_path: String, id: i64) -> Result<(), String> { + local_db::update_session_access(&repo_path, id) +} + +#[tauri::command] +pub fn update_session_name(repo_path: String, id: i64, name: String) -> Result<(), String> { + local_db::update_session_name(&repo_path, id, name) +} + +#[tauri::command] +pub fn delete_session(repo_path: String, id: i64) -> Result<(), String> { + local_db::delete_session(&repo_path, id) +} + +#[tauri::command] +pub fn get_session_model(repo_path: String, id: i64) -> Result, String> { + local_db::get_session_model(&repo_path, id) +} + +#[tauri::command] +pub fn set_session_model(repo_path: String, id: i64, model: Option) -> Result<(), String> { + local_db::set_session_model(&repo_path, id, model) +} diff --git a/src-tauri/src/commands/settings.rs b/src-tauri/src/commands/settings.rs new file mode 100644 index 00000000..c7ed9354 --- /dev/null +++ b/src-tauri/src/commands/settings.rs @@ -0,0 +1,44 @@ +use std::collections::HashMap; +use tauri::State; +use crate::AppState; + +#[tauri::command] +pub fn get_setting(state: State, key: String) -> Result, String> { + let db = state.db.lock().unwrap(); + db.get_setting(&key).map_err(|e| e.to_string()) +} + +#[tauri::command] +pub fn get_settings_batch(state: State, keys: Vec) -> Result>, String> { + let db = state.db.lock().unwrap(); + db.get_settings_batch(&keys).map_err(|e| e.to_string()) +} + +#[tauri::command] +pub fn set_setting(state: State, key: String, value: String) -> Result<(), String> { + let db = state.db.lock().unwrap(); + db.set_setting(&key, &value).map_err(|e| e.to_string()) +} + +#[tauri::command] +pub fn get_repo_setting( + state: State, + repo_path: String, + key: String, +) -> Result, String> { + let db = state.db.lock().unwrap(); + db.get_repo_setting(&repo_path, &key) + .map_err(|e| e.to_string()) +} + +#[tauri::command] +pub fn set_repo_setting( + state: State, + repo_path: String, + key: String, + value: String, +) -> Result<(), String> { + let db = state.db.lock().unwrap(); + db.set_repo_setting(&repo_path, &key, &value) + .map_err(|e| e.to_string()) +} diff --git a/src-tauri/src/commands/workspace.rs b/src-tauri/src/commands/workspace.rs new file mode 100644 index 00000000..a1592e7c --- /dev/null +++ b/src-tauri/src/commands/workspace.rs @@ -0,0 +1,95 @@ +use crate::db::Workspace; +use crate::local_db; +use crate::jj::{self, JjRebaseResult}; +use std::collections::HashSet; +use std::sync::{Mutex, OnceLock}; + +// Track which workspaces have been indexed this session +static INDEXED_WORKSPACES: OnceLock>> = OnceLock::new(); + +#[tauri::command] +pub fn get_workspaces(repo_path: String) -> Result, String> { + local_db::get_workspaces(&repo_path) +} + +#[tauri::command] +pub fn add_workspace_to_db( + repo_path: String, + workspace_name: String, + workspace_path: String, + branch_name: String, + metadata: Option, +) -> Result { + local_db::add_workspace(&repo_path, workspace_name, workspace_path, branch_name, metadata) +} + +#[tauri::command] +pub fn delete_workspace_from_db(repo_path: String, id: i64) -> Result<(), String> { + // Cascade delete sessions (handled by DB foreign key constraint) + local_db::delete_workspace(&repo_path, id) +} + +#[tauri::command] +pub fn rebuild_workspaces(repo_path: String) -> Result, String> { + local_db::rebuild_workspaces_from_filesystem(&repo_path) +} + +#[tauri::command] +pub fn update_workspace_metadata( + repo_path: String, + id: i64, + metadata: String, +) -> Result<(), String> { + local_db::update_workspace_metadata(&repo_path, id, &metadata) +} + +#[tauri::command] +pub fn ensure_workspace_indexed( + repo_path: String, + workspace_id: Option, + workspace_path: String, +) -> Result { + let indexed = INDEXED_WORKSPACES.get_or_init(|| Mutex::new(HashSet::new())); + let mut guard = indexed.lock().unwrap(); + + // Use workspace_path as the key + if guard.contains(&workspace_path) { + // Already indexed this session + return Ok(false); + } + + // Mark as indexed + guard.insert(workspace_path.clone()); + drop(guard); + + // Trigger indexing + crate::file_indexer::index_workspace_files(&repo_path, workspace_id, &workspace_path)?; + + Ok(true) +} + +#[tauri::command] +pub fn set_workspace_target_branch( + repo_path: String, + workspace_path: String, + id: i64, + target_branch: String, +) -> Result { + // Convert Git remote branch format (origin/main) to jj format (main@origin) + let jj_branch_name = if target_branch.starts_with("origin/") { + target_branch.replace("origin/", "") + "@origin" + } else { + target_branch.clone() + }; + + // Perform rebase + let rebase_result = jj::jj_rebase_onto(&workspace_path, &jj_branch_name) + .map_err(|e| e.to_string())?; + + // If rebase succeeded (even with conflicts), save the target branch (in Git format for UI) + if rebase_result.success || rebase_result.has_conflicts { + local_db::update_workspace_target_branch(&repo_path, id, &target_branch)?; + } + + Ok(rebase_result) +} diff --git a/src-tauri/src/db.rs b/src-tauri/src/db.rs index ebde132d..a45da781 100644 --- a/src-tauri/src/db.rs +++ b/src-tauri/src/db.rs @@ -13,7 +13,7 @@ pub struct Workspace { pub branch_name: String, pub created_at: String, pub metadata: Option, - pub is_pinned: bool, + pub target_branch: Option, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -23,7 +23,6 @@ pub struct Session { pub name: String, pub created_at: String, pub last_accessed: String, - pub plan_title: Option, pub model: Option, } @@ -48,12 +47,17 @@ pub struct FileView { pub struct Database { conn: Connection, + db_path: PathBuf, } impl Database { pub fn new(db_path: PathBuf) -> Result { - let conn = Connection::open(db_path)?; - Ok(Database { conn }) + let conn = Connection::open(&db_path)?; + Ok(Database { conn, db_path }) + } + + pub fn db_path(&self) -> &PathBuf { + &self.db_path } pub fn init(&self) -> Result<()> { @@ -73,18 +77,12 @@ impl Database { name TEXT NOT NULL, created_at TEXT NOT NULL, last_accessed TEXT NOT NULL, - plan_title TEXT, model TEXT, FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE )", [], )?; - // Migration: Add plan_title column if it doesn't exist - let _ = self - .conn - .execute("ALTER TABLE sessions ADD COLUMN plan_title TEXT", []); - // Migration: Add model column if it doesn't exist let _ = self .conn @@ -221,55 +219,6 @@ impl Database { Ok(()) } - #[allow(dead_code)] - pub fn add_workspace(&self, workspace: &Workspace) -> Result { - self.conn.execute( - "INSERT INTO workspaces (repo_path, workspace_name, workspace_path, branch_name, created_at, metadata) - VALUES (?1, ?2, ?3, ?4, ?5, ?6)", - ( - &workspace.repo_path, - &workspace.workspace_name, - &workspace.workspace_path, - &workspace.branch_name, - &workspace.created_at, - &workspace.metadata, - ), - )?; - Ok(self.conn.last_insert_rowid()) - } - - #[allow(dead_code)] - pub fn get_workspaces(&self) -> Result> { - let mut stmt = self.conn.prepare( - "SELECT id, repo_path, workspace_name, workspace_path, branch_name, created_at, metadata, is_pinned - FROM workspaces ORDER BY is_pinned DESC, branch_name COLLATE NOCASE ASC", - )?; - - let workspaces = stmt.query_map([], |row| { - Ok(Workspace { - id: row.get(0)?, - repo_path: row.get(1)?, - workspace_name: row.get(2)?, - workspace_path: row.get(3)?, - branch_name: row.get(4)?, - created_at: row.get(5)?, - metadata: row.get(6)?, - is_pinned: row.get::<_, i64>(7)? != 0, - }) - })?; - - workspaces.collect() - } - - #[allow(dead_code)] - pub fn delete_workspace(&self, id: i64) -> Result<()> { - self.conn - .execute("DELETE FROM sessions WHERE workspace_id = ?1", [id])?; - self.conn - .execute("DELETE FROM workspaces WHERE id = ?1", [id])?; - Ok(()) - } - pub fn get_setting(&self, key: &str) -> Result> { let mut stmt = self .conn @@ -291,6 +240,38 @@ impl Database { Ok(()) } + pub fn get_settings_batch(&self, keys: &[String]) -> Result>> { + use std::collections::HashMap; + + let mut result = HashMap::new(); + + if keys.is_empty() { + return Ok(result); + } + + // Build placeholders for IN clause + let placeholders = keys.iter().map(|_| "?").collect::>().join(", "); + let query = format!("SELECT key, value FROM settings WHERE key IN ({})", placeholders); + + let mut stmt = self.conn.prepare(&query)?; + let params: Vec<&dyn rusqlite::ToSql> = keys.iter().map(|k| k as &dyn rusqlite::ToSql).collect(); + let mut rows = stmt.query(¶ms[..])?; + + // First, initialize all keys with None + for key in keys { + result.insert(key.clone(), None); + } + + // Then populate with actual values + while let Some(row) = rows.next()? { + let key: String = row.get(0)?; + let value: String = row.get(1)?; + result.insert(key, Some(value)); + } + + Ok(result) + } + // Helper function to create composite key for repo-specific settings fn make_repo_key(repo_path: &str, key: &str) -> String { let mut hasher = Sha256::new(); @@ -367,26 +348,16 @@ impl Database { Ok(()) } - #[allow(dead_code)] - pub fn get_all_cached_workspaces(&self) -> Result> { - let mut stmt = self - .conn - .prepare("SELECT DISTINCT workspace_path FROM git_cache ORDER BY workspace_path")?; - let rows = stmt.query_map([], |row| row.get(0))?; - rows.collect() - } - #[allow(dead_code)] pub fn add_session(&self, session: &Session) -> Result { self.conn.execute( - "INSERT INTO sessions (workspace_id, type, name, created_at, last_accessed, plan_title, model) - VALUES (?1, 'session', ?2, ?3, ?4, ?5, ?6)", + "INSERT INTO sessions (workspace_id, type, name, created_at, last_accessed, model) + VALUES (?1, 'session', ?2, ?3, ?4, ?5)", ( &session.workspace_id, &session.name, &session.created_at, &session.last_accessed, - &session.plan_title, &session.model, ), )?; @@ -396,7 +367,7 @@ impl Database { #[allow(dead_code)] pub fn get_sessions(&self) -> Result> { let mut stmt = self.conn.prepare( - "SELECT id, workspace_id, name, created_at, last_accessed, plan_title, model + "SELECT id, workspace_id, name, created_at, last_accessed, model FROM sessions ORDER BY created_at ASC", )?; @@ -407,52 +378,7 @@ impl Database { name: row.get(2)?, created_at: row.get(3)?, last_accessed: row.get(4)?, - plan_title: row.get(5)?, - model: row.get(6)?, - }) - })?; - - sessions.collect() - } - - #[allow(dead_code)] - pub fn get_sessions_by_workspace(&self, workspace_id: i64) -> Result> { - let mut stmt = self.conn.prepare( - "SELECT id, workspace_id, name, created_at, last_accessed, plan_title, model - FROM sessions WHERE workspace_id = ?1 ORDER BY created_at ASC", - )?; - - let sessions = stmt.query_map([workspace_id], |row| { - Ok(Session { - id: row.get(0)?, - workspace_id: row.get(1)?, - name: row.get(2)?, - created_at: row.get(3)?, - last_accessed: row.get(4)?, - plan_title: row.get(5)?, - model: row.get(6)?, - }) - })?; - - sessions.collect() - } - - #[allow(dead_code)] - pub fn get_main_repo_sessions(&self) -> Result> { - let mut stmt = self.conn.prepare( - "SELECT id, workspace_id, name, created_at, last_accessed, plan_title, model - FROM sessions WHERE workspace_id IS NULL ORDER BY created_at ASC", - )?; - - let sessions = stmt.query_map([], |row| { - Ok(Session { - id: row.get(0)?, - workspace_id: row.get(1)?, - name: row.get(2)?, - created_at: row.get(3)?, - last_accessed: row.get(4)?, - plan_title: row.get(5)?, - model: row.get(6)?, + model: row.get(5)?, }) })?; diff --git a/src-tauri/src/file_indexer.rs b/src-tauri/src/file_indexer.rs new file mode 100644 index 00000000..a057e2f0 --- /dev/null +++ b/src-tauri/src/file_indexer.rs @@ -0,0 +1,274 @@ +use crate::jj; +use crate::local_db::{self, CachedWorkspaceFile}; +use chrono::Utc; +use std::collections::HashSet; +use std::path::{Path, PathBuf}; +use std::process::Command; + +/// Get list of git-tracked files for a workspace +/// Uses `git ls-files` to get both cached and untracked files (respecting .gitignore) +pub fn get_git_tracked_files(workspace_path: &str) -> Result, String> { + let output = Command::new("git") + .args(["ls-files", "--cached", "--others", "--exclude-standard"]) + .current_dir(workspace_path) + .output() + .map_err(|e| format!("Failed to run git ls-files: {}", e))?; + + if !output.status.success() { + return Err(format!( + "git ls-files failed: {}", + String::from_utf8_lossy(&output.stderr) + )); + } + + let files: Vec = String::from_utf8_lossy(&output.stdout) + .lines() + .map(|s| s.trim().to_string()) + .filter(|s| !s.is_empty()) + .collect(); + + Ok(files) +} + +/// Get list of files from jj status (changed files only) +/// Uses `jj status` to get only files that have been modified, added, or deleted +pub fn get_jj_status_files(workspace_path: &str) -> Result, String> { + let changes = jj::jj_get_changed_files(workspace_path) + .map_err(|e| format!("Failed to get jj status: {}", e))?; + + Ok(changes.into_iter().map(|c| c.path).collect()) +} + +/// Get file modification time as unix timestamp +fn get_file_mtime(path: &Path) -> Option { + std::fs::metadata(path) + .ok() + .and_then(|metadata| metadata.modified().ok()) + .and_then(|mtime| mtime.duration_since(std::time::UNIX_EPOCH).ok()) + .map(|duration| duration.as_secs() as i64) +} + +/// Build a hierarchical file tree from a flat list of file paths +/// Creates directory entries with parent_path relationships for efficient querying +fn build_file_tree( + workspace_path: &str, + files: Vec, +) -> Result, String> { + let workspace_path_buf = Path::new(workspace_path); + let mut cached_files = Vec::new(); + let mut directories_seen = HashSet::new(); + let cached_at = Utc::now().to_rfc3339(); + + // First pass: create entries for all files + for file_path in files { + let full_path = workspace_path_buf.join(&file_path); + let full_path_str = full_path + .to_str() + .ok_or_else(|| format!("Invalid file path: {:?}", full_path))? + .to_string(); + + // Determine parent path + let parent_path = if let Some(parent) = full_path.parent() { + if parent == workspace_path_buf { + // Root level file + Some(workspace_path.to_string()) + } else { + parent.to_str().map(|s| s.to_string()) + } + } else { + Some(workspace_path.to_string()) + }; + + cached_files.push(CachedWorkspaceFile { + id: 0, // Will be auto-generated by database + workspace_id: None, // Will be set by caller + file_path: full_path_str.clone(), + relative_path: file_path.clone(), + is_directory: false, + parent_path, + cached_at: cached_at.clone(), + mtime: get_file_mtime(&full_path), + }); + + // Collect all directory components + let path = Path::new(&file_path); + let mut current = PathBuf::new(); + for component in path.components() { + if let Some(comp_str) = component.as_os_str().to_str() { + current.push(comp_str); + if current != path { + // This is a directory component + directories_seen.insert(current.to_string_lossy().to_string()); + } + } + } + } + + // Second pass: create directory entries + for dir_rel_path in directories_seen { + let full_dir_path = workspace_path_buf.join(&dir_rel_path); + let full_dir_path_str = full_dir_path + .to_str() + .ok_or_else(|| format!("Invalid directory path: {:?}", full_dir_path))? + .to_string(); + + let parent_path = if let Some(parent) = full_dir_path.parent() { + if parent == workspace_path_buf { + Some(workspace_path.to_string()) + } else { + parent.to_str().map(|s| s.to_string()) + } + } else { + Some(workspace_path.to_string()) + }; + + cached_files.push(CachedWorkspaceFile { + id: 0, + workspace_id: None, + file_path: full_dir_path_str, + relative_path: dir_rel_path, + is_directory: true, + parent_path, + cached_at: cached_at.clone(), + mtime: get_file_mtime(&full_dir_path), + }); + } + + Ok(cached_files) +} + +/// Index workspace files into database +/// Gets files from jj status (changed files only) and builds a hierarchical cache +pub fn index_workspace_files( + repo_path: &str, + workspace_id: Option, + workspace_path: &str, +) -> Result<(), String> { + // Get only changed files from jj status + let files = get_jj_status_files(workspace_path)?; + + // Build file tree with parent relationships + let mut cached_files = build_file_tree(workspace_path, files)?; + + // Set workspace_id for all entries + for file in &mut cached_files { + file.workspace_id = workspace_id; + } + + // Sync to database + local_db::sync_workspace_files(repo_path, workspace_id, cached_files)?; + + Ok(()) +} + +/// Incrementally update specific files in the index +/// Only updates the files that have actually changed, instead of full replacement +pub fn index_changed_files( + repo_path: &str, + workspace_id: Option, + workspace_path: &str, + changed_paths: Vec, +) -> Result<(), String> { + if changed_paths.is_empty() { + return Ok(()); + } + + let workspace_path_buf = Path::new(workspace_path); + let mut files_to_delete = Vec::new(); + let mut directories_seen = HashSet::new(); + + // Process each changed file + for file_path in &changed_paths { + let full_path = workspace_path_buf.join(file_path); + + if full_path.exists() { + // File exists - upsert it + let full_path_str = full_path + .to_str() + .ok_or_else(|| format!("Invalid file path: {:?}", full_path))? + .to_string(); + + let parent_path = if let Some(parent) = full_path.parent() { + if parent == workspace_path_buf { + Some(workspace_path) + } else { + parent.to_str() + } + } else { + Some(workspace_path) + }; + + let is_directory = full_path.is_dir(); + let mtime = if is_directory { + get_file_mtime(&full_path) + } else { + get_file_mtime(&full_path) + }; + + local_db::upsert_workspace_file( + repo_path, + workspace_id, + &full_path_str, + file_path, + is_directory, + parent_path, + mtime, + )?; + + // Collect parent directories + let path = Path::new(file_path); + let mut current = PathBuf::new(); + for component in path.components() { + if let Some(comp_str) = component.as_os_str().to_str() { + current.push(comp_str); + if current != path { + directories_seen.insert(current.to_string_lossy().to_string()); + } + } + } + } else { + // File was deleted - mark for removal + let full_path_str = full_path + .to_str() + .ok_or_else(|| format!("Invalid file path: {:?}", full_path))? + .to_string(); + files_to_delete.push(full_path_str); + } + } + + // Upsert parent directories + for dir_rel_path in directories_seen { + let full_dir_path = workspace_path_buf.join(&dir_rel_path); + let full_dir_path_str = full_dir_path + .to_str() + .ok_or_else(|| format!("Invalid directory path: {:?}", full_dir_path))? + .to_string(); + + let parent_path = if let Some(parent) = full_dir_path.parent() { + if parent == workspace_path_buf { + Some(workspace_path) + } else { + parent.to_str() + } + } else { + Some(workspace_path) + }; + + local_db::upsert_workspace_file( + repo_path, + workspace_id, + &full_dir_path_str, + &dir_rel_path, + true, + parent_path, + get_file_mtime(&full_dir_path), + )?; + } + + // Delete files that no longer exist + if !files_to_delete.is_empty() { + local_db::delete_workspace_files(repo_path, workspace_id, files_to_delete)?; + } + + Ok(()) +} diff --git a/src-tauri/src/git.rs b/src-tauri/src/git.rs deleted file mode 100644 index f7770ca6..00000000 --- a/src-tauri/src/git.rs +++ /dev/null @@ -1,867 +0,0 @@ -use globset::{Glob, GlobSetBuilder}; -use ignore::WalkBuilder; -use serde::{Deserialize, Serialize}; -use std::fs; -use std::path::Path; -use std::process::Command; -use walkdir::WalkDir; - -#[derive(Debug, Serialize, Deserialize)] -pub struct GitStatus { - pub modified: usize, - pub added: usize, - pub deleted: usize, - pub untracked: usize, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct BranchInfo { - pub name: String, - pub ahead: usize, - pub behind: usize, - pub upstream: Option, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct BranchDivergence { - pub ahead: usize, - pub behind: usize, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct WorkspaceInfo { - pub path: String, - pub branch: String, - pub commit: String, -} - -pub fn create_workspace( - repo_path: &str, - branch: &str, - new_branch: bool, - source_branch: Option<&str>, - inclusion_patterns: Option>, -) -> Result { - // Sanitize branch name for path - let sanitized = sanitize_branch_name_for_path(branch); - - // Generate workspace path: {repo_path}/.treq/workspaces/{sanitized_branch} - let workspace_path = format!("{}/.treq/workspaces/{}", repo_path, sanitized); - - // Create .treq/workspaces directory if it doesn't exist - let treq_dir = format!("{}/.treq/workspaces", repo_path); - fs::create_dir_all(&treq_dir) - .map_err(|e| format!("Failed to create .treq/workspaces directory: {}", e))?; - - // Check if workspace already exists at this path - if Path::new(&workspace_path).exists() { - return Err(format!("Workspace already exists at {}", workspace_path)); - } - - // Execute git worktree add command (internal Git operation - command name stays as-is) - // When new_branch is true and source_branch is provided: - // git worktree add -b - // When new_branch is true and no source_branch: - // git worktree add -b - // When new_branch is false: - // git worktree add - let mut cmd = Command::new("git"); - cmd.current_dir(repo_path); - cmd.arg("worktree").arg("add"); - - if new_branch { - cmd.arg("-b").arg(branch); - } - - cmd.arg(&workspace_path); - - if new_branch { - // If source_branch is provided, use it as the base for the new branch - if let Some(source) = source_branch { - cmd.arg(source); - } - } else { - cmd.arg(branch); - } - - let output = cmd.output().map_err(|e| e.to_string())?; - - if output.status.success() { - // Copy selected ignored files after successful workspace creation - if let Some(patterns) = inclusion_patterns { - if let Err(e) = copy_ignored_files(repo_path, &workspace_path, patterns) { - eprintln!("Warning: Failed to copy ignored files: {}", e); - // Don't fail the workspace creation, just log the warning - } - } - - // Return the workspace path instead of stdout - Ok(workspace_path) - } else { - Err(String::from_utf8_lossy(&output.stderr).to_string()) - } -} - -/// Create a git workspace at a specific path (used by jj workspace creation) -pub fn create_workspace_at_path( - repo_path: &str, - branch: &str, - new_branch: bool, - source_branch: Option<&str>, - workspace_path: &str, -) -> Result { - // Check if workspace already exists at this path - if Path::new(workspace_path).exists() { - return Err(format!("Workspace already exists at {}", workspace_path)); - } - - // Execute git worktree add command (internal Git operation - command name stays as-is) - let mut cmd = Command::new("git"); - cmd.current_dir(repo_path); - cmd.arg("worktree").arg("add"); - - if new_branch { - cmd.arg("-b").arg(branch); - } - - cmd.arg(workspace_path); - - if new_branch { - if let Some(source) = source_branch { - cmd.arg(source); - } - } else { - cmd.arg(branch); - } - - let output = cmd.output().map_err(|e| e.to_string())?; - - if output.status.success() { - Ok(workspace_path.to_string()) - } else { - Err(String::from_utf8_lossy(&output.stderr).to_string()) - } -} - -pub fn list_workspaces(repo_path: &str) -> Result, String> { - let output = Command::new("git") - .current_dir(repo_path) - .args(["worktree", "list", "--porcelain"]) - .output() - .map_err(|e| e.to_string())?; - - if !output.status.success() { - return Err(String::from_utf8_lossy(&output.stderr).to_string()); - } - - let stdout = String::from_utf8_lossy(&output.stdout); - let mut workspaces = Vec::new(); - let mut current_workspace: Option = None; - - // Parse git's porcelain output format (lines like "worktree /path", "branch refs/heads/main", "HEAD abc123") - for line in stdout.lines() { - if line.starts_with("worktree ") { - if let Some(wt) = current_workspace.take() { - workspaces.push(wt); - } - current_workspace = Some(WorkspaceInfo { - path: line.strip_prefix("worktree ").unwrap_or("").to_string(), - branch: String::new(), - commit: String::new(), - }); - } else if line.starts_with("branch ") { - if let Some(ref mut wt) = current_workspace { - wt.branch = line - .strip_prefix("branch refs/heads/") - .or_else(|| line.strip_prefix("branch ")) - .unwrap_or("") - .to_string(); - } - } else if line.starts_with("HEAD ") { - if let Some(ref mut wt) = current_workspace { - wt.commit = line.strip_prefix("HEAD ").unwrap_or("").to_string(); - } - } - } - - if let Some(wt) = current_workspace { - workspaces.push(wt); - } - - Ok(workspaces) -} - -pub fn remove_workspace(repo_path: &str, workspace_path: &str) -> Result { - // Use --force because the UI already prompts the user for confirmation - let output = Command::new("git") - .current_dir(repo_path) - .args(["worktree", "remove", "--force", workspace_path]) - .output() - .map_err(|e| e.to_string())?; - - if output.status.success() { - Ok(String::from_utf8_lossy(&output.stdout).to_string()) - } else { - Err(String::from_utf8_lossy(&output.stderr).to_string()) - } -} - -pub fn get_git_status(workspace_path: &str) -> Result { - // Get tracked file changes (modified, added, deleted, staged) - let output = Command::new("git") - .current_dir(workspace_path) - .args(["status", "--porcelain"]) - .output() - .map_err(|e| e.to_string())?; - - if !output.status.success() { - return Err(String::from_utf8_lossy(&output.stderr).to_string()); - } - - let stdout = String::from_utf8_lossy(&output.stdout); - let mut status = GitStatus { - modified: 0, - added: 0, - deleted: 0, - untracked: 0, - }; - - for line in stdout.lines() { - if line.len() < 3 { - continue; - } - - let chars: Vec = line.chars().collect(); - // Skip untracked files from porcelain output (we'll count them separately) - if chars[0] == '?' && chars[1] == '?' { - continue; - } - - match chars[0] { - 'M' => status.modified += 1, - 'A' => status.added += 1, - 'D' => status.deleted += 1, - _ => {} - } - if chars.len() > 1 { - match chars[1] { - 'M' => status.modified += 1, - 'D' => status.deleted += 1, - _ => {} - } - } - } - - // Get untracked files count (individual files, respecting .gitignore) - let untracked_output = Command::new("git") - .current_dir(workspace_path) - .args(["ls-files", "--others", "--exclude-standard"]) - .output() - .map_err(|e| e.to_string())?; - - if untracked_output.status.success() { - let untracked_stdout = String::from_utf8_lossy(&untracked_output.stdout); - status.untracked = untracked_stdout - .lines() - .filter(|line| !line.is_empty()) - .count(); - } - - Ok(status) -} - -pub fn get_branch_info(workspace_path: &str) -> Result { - // Get current branch name - let branch_output = Command::new("git") - .current_dir(workspace_path) - .args(["rev-parse", "--abbrev-ref", "HEAD"]) - .output() - .map_err(|e| e.to_string())?; - - let branch_name = String::from_utf8_lossy(&branch_output.stdout) - .trim() - .to_string(); - - // Get upstream branch - let upstream_output = Command::new("git") - .current_dir(workspace_path) - .args(["rev-parse", "--abbrev-ref", "@{upstream}"]) - .output() - .ok(); - - let upstream = upstream_output.and_then(|o| { - if o.status.success() { - Some(String::from_utf8_lossy(&o.stdout).trim().to_string()) - } else { - None - } - }); - - // Get ahead/behind counts - let (ahead, behind) = if let Some(ref up) = upstream { - let rev_output = Command::new("git") - .current_dir(workspace_path) - .args([ - "rev-list", - "--left-right", - "--count", - &format!("{}...{}", up, branch_name), - ]) - .output() - .ok(); - - if let Some(output) = rev_output { - let counts = String::from_utf8_lossy(&output.stdout); - let parts: Vec<&str> = counts.trim().split_whitespace().collect(); - if parts.len() == 2 { - let behind = parts[0].parse().unwrap_or(0); - let ahead = parts[1].parse().unwrap_or(0); - (ahead, behind) - } else { - (0, 0) - } - } else { - (0, 0) - } - } else { - (0, 0) - }; - - Ok(BranchInfo { - name: branch_name, - ahead, - behind, - upstream, - }) -} - -pub fn get_branch_divergence( - workspace_path: &str, - base_branch: &str, -) -> Result { - if base_branch.trim().is_empty() { - return Err("Base branch name is required".to_string()); - } - - let branch_output = Command::new("git") - .current_dir(workspace_path) - .args(["rev-parse", "--abbrev-ref", "HEAD"]) - .output() - .map_err(|e| e.to_string())?; - - if !branch_output.status.success() { - return Err(String::from_utf8_lossy(&branch_output.stderr).to_string()); - } - - let branch_name = String::from_utf8_lossy(&branch_output.stdout) - .trim() - .to_string(); - - let rev_output = Command::new("git") - .current_dir(workspace_path) - .args([ - "rev-list", - "--left-right", - "--count", - &format!("{}...{}", base_branch, branch_name), - ]) - .output() - .map_err(|e| e.to_string())?; - - if !rev_output.status.success() { - return Err(String::from_utf8_lossy(&rev_output.stderr).to_string()); - } - - let counts = String::from_utf8_lossy(&rev_output.stdout); - let parts: Vec<&str> = counts.trim().split_whitespace().collect(); - let behind = parts - .get(0) - .and_then(|s| s.parse::().ok()) - .unwrap_or(0); - let ahead = parts - .get(1) - .and_then(|s| s.parse::().ok()) - .unwrap_or(0); - - Ok(BranchDivergence { ahead, behind }) -} - -pub fn list_branches(repo_path: &str) -> Result, String> { - let output = Command::new("git") - .current_dir(repo_path) - .args(["branch", "-a", "--format=%(refname:short)"]) - .output() - .map_err(|e| e.to_string())?; - - if output.status.success() { - Ok(String::from_utf8_lossy(&output.stdout) - .lines() - .map(|s| s.to_string()) - .collect()) - } else { - Err(String::from_utf8_lossy(&output.stderr).to_string()) - } -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct BranchListItem { - pub name: String, - pub full_name: String, - pub is_remote: bool, - pub is_current: bool, -} - -pub fn list_branches_detailed(repo_path: &str) -> Result, String> { - // Get current branch - let current_branch = get_current_branch(repo_path).ok(); - - // Get all branches with their ref names - let output = Command::new("git") - .current_dir(repo_path) - .args(["branch", "-a", "--format=%(refname:short)\t%(HEAD)"]) - .output() - .map_err(|e| e.to_string())?; - - if !output.status.success() { - return Err(String::from_utf8_lossy(&output.stderr).to_string()); - } - - let mut branches = Vec::new(); - let stdout = String::from_utf8_lossy(&output.stdout); - - for line in stdout.lines() { - let parts: Vec<&str> = line.split('\t').collect(); - if parts.is_empty() { - continue; - } - - let full_name = parts[0].trim(); - let is_current = parts.get(1).map(|s| s.trim() == "*").unwrap_or(false); - - // Skip HEAD references - if full_name.contains("HEAD") { - continue; - } - - // Determine if remote and extract clean name - let (name, is_remote) = if full_name.starts_with("remotes/") { - let clean_name = full_name.strip_prefix("remotes/").unwrap_or(full_name); - // For remote branches, show the remote name too - (clean_name.to_string(), true) - } else { - (full_name.to_string(), false) - }; - - branches.push(BranchListItem { - name: name.clone(), - full_name: full_name.to_string(), - is_remote, - is_current: is_current || current_branch.as_ref().map(|cb| cb == full_name).unwrap_or(false), - }); - } - - // Sort: current first, then local branches, then remote branches - branches.sort_by(|a, b| { - if a.is_current != b.is_current { - return b.is_current.cmp(&a.is_current); - } - if a.is_remote != b.is_remote { - return a.is_remote.cmp(&b.is_remote); - } - a.name.cmp(&b.name) - }); - - Ok(branches) -} - -pub fn checkout_branch(repo_path: &str, branch_name: &str, create_new: bool) -> Result { - let mut cmd = Command::new("git"); - cmd.current_dir(repo_path).arg("checkout"); - - if create_new { - cmd.arg("-b"); - } - - cmd.arg(branch_name); - - let output = cmd.output().map_err(|e| e.to_string())?; - - if output.status.success() { - Ok(String::from_utf8_lossy(&output.stdout).to_string()) - } else { - Err(String::from_utf8_lossy(&output.stderr).to_string()) - } -} - -pub fn is_git_repository(path: &str) -> Result { - let git_path = Path::new(path).join(".git"); - Ok(git_path.exists()) -} - -pub fn git_init(path: &str) -> Result { - let output = Command::new("git") - .current_dir(path) - .args(["init"]) - .output() - .map_err(|e| e.to_string())?; - - if output.status.success() { - Ok(String::from_utf8_lossy(&output.stdout).to_string()) - } else { - Err(String::from_utf8_lossy(&output.stderr).to_string()) - } -} - -pub fn get_current_branch(repo_path: &str) -> Result { - let output = Command::new("git") - .current_dir(repo_path) - .args(["rev-parse", "--abbrev-ref", "HEAD"]) - .output() - .map_err(|e| e.to_string())?; - - if output.status.success() { - let branch = String::from_utf8_lossy(&output.stdout).trim().to_string(); - - // Handle detached HEAD state - if branch == "HEAD" { - let commit_output = Command::new("git") - .current_dir(repo_path) - .args(["rev-parse", "--short", "HEAD"]) - .output() - .map_err(|e| e.to_string())?; - - if commit_output.status.success() { - let commit = String::from_utf8_lossy(&commit_output.stdout) - .trim() - .to_string(); - return Ok(format!("HEAD detached at {}", commit)); - } - } - - Ok(branch) - } else { - Err(String::from_utf8_lossy(&output.stderr).to_string()) - } -} - -/// Configure push.autoSetupRemote for the repository -/// Returns Ok(()) if successful or already configured -pub fn configure_push_auto_setup_remote(repo_path: &str) -> Result<(), String> { - let output = Command::new("git") - .current_dir(repo_path) - .args(["config", "--local", "push.autoSetupRemote", "true"]) - .output() - .map_err(|e| format!("Failed to execute git config: {}", e))?; - - if output.status.success() { - Ok(()) - } else { - Err(String::from_utf8_lossy(&output.stderr).to_string()) - } -} - -/// Ensure repository has required git configuration -/// This is idempotent and safe to call multiple times -pub fn ensure_repo_configured( - db: &crate::db::Database, - repo_path: &str, -) -> Result<(), String> { - // Check if already configured - let flag_key = "git_push_auto_setup_remote_configured"; - let already_configured = db - .get_repo_setting(repo_path, flag_key) - .ok() - .flatten() - .map(|v| v == "true") - .unwrap_or(false); - - if already_configured { - return Ok(()); - } - - // Run git config - configure_push_auto_setup_remote(repo_path)?; - - // Mark as configured - db.set_repo_setting(repo_path, flag_key, "true") - .map_err(|e| format!("Failed to save configuration flag: {}", e))?; - - Ok(()) -} - -pub fn sanitize_branch_name_for_path(branch: &str) -> String { - branch - .replace('/', "-") - .replace('\\', "-") - .replace('*', "_") - .replace('?', "_") - .replace('<', "_") - .replace('>', "_") - .replace('|', "_") - .replace('"', "_") - .replace(':', "_") - .trim_matches('.') - .trim() - .to_string() -} - -pub fn execute_post_create_command( - workspace_path: &str, - command: &str, -) -> Result { - // Split command into program and arguments - // For simplicity, we'll use shell to execute the command - // This allows complex commands with pipes, redirects, etc. - - #[cfg(target_os = "windows")] - let shell = "powershell"; - #[cfg(target_os = "windows")] - let shell_arg = "-Command"; - - #[cfg(not(target_os = "windows"))] - let shell = "sh"; - #[cfg(not(target_os = "windows"))] - let shell_arg = "-c"; - - let output = Command::new(shell) - .arg(shell_arg) - .arg(command) - .current_dir(workspace_path) - .output() - .map_err(|e| format!("Failed to execute command: {}", e))?; - - // Combine stdout and stderr - let stdout = String::from_utf8_lossy(&output.stdout); - let stderr = String::from_utf8_lossy(&output.stderr); - let combined_output = format!("{}{}", stdout, stderr); - - if output.status.success() { - Ok(combined_output) - } else { - Err(format!( - "Command failed with exit code {:?}\nOutput: {}", - output.status.code(), - combined_output - )) - } -} - -/// Copy selected ignored files from source repository to workspace -/// This function identifies files that are gitignored and copies only those matching inclusion patterns -/// If inclusion_patterns is empty, no files are copied (secure by default) -pub fn copy_ignored_files( - source_repo: &str, - dest_workspace: &str, - inclusion_patterns: Vec, -) -> Result<(), String> { - let source_path = Path::new(source_repo); - let dest_path = Path::new(dest_workspace); - - // Build glob set from inclusion patterns - let globset = if !inclusion_patterns.is_empty() { - let mut builder = GlobSetBuilder::new(); - for pattern in &inclusion_patterns { - let pattern = pattern.trim(); - if !pattern.is_empty() { - match Glob::new(pattern) { - Ok(glob) => { - builder.add(glob); - } - Err(e) => { - eprintln!("Warning: Invalid glob pattern '{}': {}", pattern, e); - } - } - } - } - match builder.build() { - Ok(gs) => Some(gs), - Err(e) => { - eprintln!("Warning: Failed to build glob set: {}", e); - None - } - } - } else { - None - }; - - // If no inclusion patterns, don't copy anything (secure by default) - if globset.is_none() { - println!("No inclusion patterns specified, skipping ignored file copy"); - return Ok(()); - } - - // Build a walker that respects .gitignore - let walker = WalkBuilder::new(source_path) - .hidden(false) - .git_ignore(true) - .git_global(true) - .git_exclude(true) - .build(); - - // Also walk all files (including ignored) to compare - let all_files: Vec<_> = WalkDir::new(source_path) - .into_iter() - .filter_map(|e| e.ok()) - .filter(|e| e.file_type().is_file()) - .map(|e| e.path().to_path_buf()) - .collect(); - - // Collect non-ignored files - let non_ignored: std::collections::HashSet<_> = walker - .filter_map(|e| e.ok()) - .filter(|e| e.file_type().map(|t| t.is_file()).unwrap_or(false)) - .map(|e| e.path().to_path_buf()) - .collect(); - - // Find ignored files (files in all_files but not in non_ignored) - let mut copied_count = 0; - - for file_path in all_files { - // Skip .git directory - if file_path.components().any(|c| c.as_os_str() == ".git") { - continue; - } - - if !non_ignored.contains(&file_path) { - // This file is ignored - if let Ok(rel_path) = file_path.strip_prefix(source_path) { - // Check if this file matches any inclusion pattern - let should_copy = if let Some(ref gs) = globset { - gs.is_match(rel_path) - } else { - false - }; - - if !should_copy { - continue; // Skip this file - } - - let dest_file = dest_path.join(rel_path); - - // Create parent directory if needed - if let Some(parent) = dest_file.parent() { - if let Err(e) = fs::create_dir_all(parent) { - eprintln!( - "Warning: Failed to create directory {}: {}", - parent.display(), - e - ); - continue; - } - } - - // Copy the file - if let Err(e) = fs::copy(&file_path, &dest_file) { - eprintln!("Warning: Failed to copy {}: {}", file_path.display(), e); - } else { - copied_count += 1; - } - } - } - } - - if copied_count > 0 { - println!( - "Copied {} ignored files matching inclusion patterns to workspace", - copied_count - ); - } - - Ok(()) -} - -/// List gitignored files and directories at the root level of a repository -/// Excludes .treq and .vscode automatically -pub fn list_gitignored_files(repo_path: &str) -> Result, String> { - let repo = Path::new(repo_path); - - // Build a walker that respects .gitignore - let walker = WalkBuilder::new(repo) - .max_depth(Some(1)) // Only root level - .hidden(false) - .git_ignore(true) - .git_global(true) - .git_exclude(true) - .build(); - - // Walk all entries at root level - let all_entries: Vec<_> = fs::read_dir(repo) - .map_err(|e| format!("Failed to read directory: {}", e))? - .filter_map(|e| e.ok()) - .filter(|e| { - // Skip .git, .treq, and .vscode - if let Some(name) = e.file_name().to_str() { - name != ".git" && name != ".treq" && name != ".vscode" - } else { - false - } - }) - .map(|e| e.path()) - .collect(); - - // Collect non-ignored entries - let non_ignored: std::collections::HashSet<_> = walker - .filter_map(|e| e.ok()) - .map(|e| e.path().to_path_buf()) - .collect(); - - // Find ignored entries - let mut ignored_files = Vec::new(); - - for entry_path in all_entries { - if !non_ignored.contains(&entry_path) { - if let Some(name) = entry_path.file_name().and_then(|n| n.to_str()) { - ignored_files.push(name.to_string()); - } - } - } - - // Sort for consistent ordering - ignored_files.sort(); - - Ok(ignored_files) -} - -/// Stash specific files with a message -/// Uses: git stash push -m "{message}" -- file1 file2 ... -pub fn git_stash_push_files( - workspace_path: &str, - file_paths: Vec, - message: &str, -) -> Result { - if file_paths.is_empty() { - return Err("No files specified for stashing".to_string()); - } - - let mut cmd = Command::new("git"); - cmd.current_dir(workspace_path); - cmd.args(["stash", "push", "-m", message, "--"]); - - for path in &file_paths { - cmd.arg(path); - } - - let output = cmd.output().map_err(|e| e.to_string())?; - - if output.status.success() { - Ok(String::from_utf8_lossy(&output.stdout).to_string()) - } else { - Err(String::from_utf8_lossy(&output.stderr).to_string()) - } -} - -/// Pop the most recent stash -/// Uses: git stash pop -pub fn git_stash_pop(workspace_path: &str) -> Result { - let output = Command::new("git") - .current_dir(workspace_path) - .args(["stash", "pop"]) - .output() - .map_err(|e| e.to_string())?; - - if output.status.success() { - Ok(String::from_utf8_lossy(&output.stdout).to_string()) - } else { - Err(String::from_utf8_lossy(&output.stderr).to_string()) - } -} diff --git a/src-tauri/src/git2_ops.rs b/src-tauri/src/git2_ops.rs deleted file mode 100644 index 918ecbe3..00000000 --- a/src-tauri/src/git2_ops.rs +++ /dev/null @@ -1,151 +0,0 @@ -use git2::{Repository, StatusOptions, Status as Git2Status, BranchType}; -use crate::git::{GitStatus, BranchInfo, BranchDivergence}; - -/// Get git status using libgit2 (no subprocess) -pub fn get_status_git2(workspace_path: &str) -> Result { - let repo = Repository::open(workspace_path) - .map_err(|e| format!("Failed to open repository: {}", e))?; - - let mut opts = StatusOptions::new(); - opts.include_untracked(true) - .recurse_untracked_dirs(false) // Don't recurse to match git status behavior - .exclude_submodules(true); - - let statuses = repo.statuses(Some(&mut opts)) - .map_err(|e| format!("Failed to get status: {}", e))?; - - let mut result = GitStatus { - modified: 0, - added: 0, - deleted: 0, - untracked: 0, - }; - - for entry in statuses.iter() { - let status = entry.status(); - - // Index (staged) changes - if status.contains(Git2Status::INDEX_NEW) { - result.added += 1; - } - if status.contains(Git2Status::INDEX_MODIFIED) { - result.modified += 1; - } - if status.contains(Git2Status::INDEX_DELETED) { - result.deleted += 1; - } - - // Worktree (unstaged) changes - if status.contains(Git2Status::WT_MODIFIED) { - result.modified += 1; - } - if status.contains(Git2Status::WT_DELETED) { - result.deleted += 1; - } - if status.contains(Git2Status::WT_NEW) { - result.untracked += 1; - } - } - - Ok(result) -} - -/// Get branch info using libgit2 -pub fn get_branch_info_git2(workspace_path: &str) -> Result { - let repo = Repository::open(workspace_path) - .map_err(|e| format!("Failed to open repository: {}", e))?; - - let head = repo.head() - .map_err(|e| format!("Failed to get HEAD: {}", e))?; - - let branch_name = if head.is_branch() { - head.shorthand().unwrap_or("HEAD").to_string() - } else { - // Detached HEAD - let commit = head.peel_to_commit() - .map_err(|e| format!("Failed to get commit: {}", e))?; - format!("HEAD (detached at {})", &commit.id().to_string()[..7]) - }; - - // Get upstream info - let (upstream, ahead, behind) = if head.is_branch() { - get_upstream_info(&repo, &head) - } else { - (None, 0, 0) - }; - - Ok(BranchInfo { - name: branch_name, - ahead, - behind, - upstream, - }) -} - -fn get_upstream_info(repo: &Repository, head: &git2::Reference) -> (Option, usize, usize) { - let branch_name = match head.shorthand() { - Some(name) => name, - None => return (None, 0, 0), - }; - - let branch = match repo.find_branch(branch_name, BranchType::Local) { - Ok(b) => b, - Err(_) => return (None, 0, 0), - }; - - let upstream = match branch.upstream() { - Ok(u) => u, - Err(_) => return (None, 0, 0), - }; - - let upstream_name = upstream.name() - .ok() - .flatten() - .map(|s| s.to_string()); - - // Calculate ahead/behind - let local_oid = match head.target() { - Some(oid) => oid, - None => return (upstream_name, 0, 0), - }; - - let upstream_oid = match upstream.get().target() { - Some(oid) => oid, - None => return (upstream_name, 0, 0), - }; - - let (ahead, behind) = match repo.graph_ahead_behind(local_oid, upstream_oid) { - Ok(counts) => counts, - Err(_) => (0, 0), - }; - - (upstream_name, ahead, behind) -} - -/// Get divergence from base branch using libgit2 -pub fn get_divergence_git2( - workspace_path: &str, - base_branch: &str, -) -> Result { - let repo = Repository::open(workspace_path) - .map_err(|e| format!("Failed to open repository: {}", e))?; - - let head = repo.head() - .map_err(|e| format!("Failed to get HEAD: {}", e))?; - - let head_oid = head.target() - .ok_or("Failed to get HEAD target")?; - - // Try to find base branch locally first, then in remotes - let base_ref = repo.find_reference(&format!("refs/heads/{}", base_branch)) - .or_else(|_| repo.find_reference(&format!("refs/remotes/origin/{}", base_branch))) - .map_err(|e| format!("Failed to find base branch '{}': {}", base_branch, e))?; - - let base_oid = base_ref.target() - .ok_or("Failed to get base branch target")?; - - let (ahead, behind) = repo.graph_ahead_behind(head_oid, base_oid) - .map_err(|e| format!("Failed to calculate divergence: {}", e))?; - - Ok(BranchDivergence { ahead, behind }) -} diff --git a/src-tauri/src/git_ops.rs b/src-tauri/src/git_ops.rs deleted file mode 100644 index 5dbec2d2..00000000 --- a/src-tauri/src/git_ops.rs +++ /dev/null @@ -1,1389 +0,0 @@ -use serde::Serialize; -use std::collections::HashMap; -use std::io::Write; -use std::process::{Command, Stdio}; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum MergeStrategy { - Regular, - Squash, - NoFastForward, - FastForwardOnly, -} - -#[derive(Debug, Serialize)] -pub struct DiffHunk { - pub id: String, - pub header: String, - pub lines: Vec, - pub is_staged: bool, - pub patch: String, -} - -#[derive(Debug, Serialize)] -pub struct FileLines { - pub lines: Vec, - pub start_line: usize, - pub end_line: usize, -} - -#[derive(Debug, Serialize, Clone, Copy)] -#[serde(rename_all = "snake_case")] -pub enum DiffLineKind { - Context, - Addition, - Deletion, - Meta, -} - -#[derive(Debug, Serialize)] -pub struct BranchDiffLine { - pub content: String, - pub kind: DiffLineKind, - pub old_line: Option, - pub new_line: Option, -} - -#[derive(Debug, Serialize)] -pub struct BranchDiffHunk { - pub header: String, - pub lines: Vec, -} - -#[derive(Debug, Serialize)] -pub struct BranchDiffFileDiff { - pub path: String, - pub previous_path: Option, - pub status: String, - pub is_binary: bool, - pub binary_message: Option, - pub metadata: Vec, - pub hunks: Vec, -} - -#[derive(Debug, Serialize, Clone)] -pub struct BranchDiffFileChange { - pub path: String, - pub previous_path: Option, - pub status: String, -} - -#[derive(Debug, Serialize)] -pub struct BranchCommitInfo { - pub hash: String, - pub abbreviated_hash: String, - pub author_name: String, - pub author_email: String, - pub date: String, - pub message: String, -} - -#[derive(Debug, Serialize)] -pub struct LineDiffStats { - pub lines_added: usize, - pub lines_deleted: usize, -} - -/// Execute git commit with message -pub fn git_commit(workspace_path: &str, message: &str) -> Result { - let output = Command::new("git") - .current_dir(workspace_path) - .args(["commit", "-m", message]) - .output() - .map_err(|e| e.to_string())?; - - if output.status.success() { - Ok(String::from_utf8_lossy(&output.stdout).to_string()) - } else { - Err(String::from_utf8_lossy(&output.stderr).to_string()) - } -} - -pub fn git_merge( - repo_path: &str, - branch: &str, - strategy: MergeStrategy, - commit_message: Option<&str>, -) -> Result { - let mut cmd = Command::new("git"); - cmd.current_dir(repo_path).arg("merge"); - - match strategy { - MergeStrategy::Regular => {} - MergeStrategy::Squash => { - cmd.arg("--squash"); - } - MergeStrategy::NoFastForward => { - cmd.arg("--no-ff"); - } - MergeStrategy::FastForwardOnly => { - cmd.arg("--ff-only"); - } - } - - if let Some(message) = commit_message { - let trimmed = message.trim(); - if !trimmed.is_empty() - && strategy != MergeStrategy::Squash - && strategy != MergeStrategy::FastForwardOnly - { - cmd.arg("-m").arg(trimmed); - } - } - - cmd.arg(branch); - - let merge_output = cmd.output().map_err(|e| e.to_string())?; - - if !merge_output.status.success() { - return Err(String::from_utf8_lossy(&merge_output.stderr).to_string()); - } - - let mut response = String::new(); - response.push_str(&String::from_utf8_lossy(&merge_output.stdout)); - if !merge_output.stderr.is_empty() { - if !response.is_empty() { - response.push('\n'); - } - response.push_str(&String::from_utf8_lossy(&merge_output.stderr)); - } - - if strategy == MergeStrategy::Squash { - let commit_msg = commit_message - .map(|msg| msg.trim().to_string()) - .filter(|msg| !msg.is_empty()) - .unwrap_or_else(|| format!("Squash merge branch {}", branch)); - - let commit_output = Command::new("git") - .current_dir(repo_path) - .args(["commit", "-m", &commit_msg]) - .output() - .map_err(|e| e.to_string())?; - - if !commit_output.status.success() { - return Err(String::from_utf8_lossy(&commit_output.stderr).to_string()); - } - - if !response.is_empty() { - response.push('\n'); - } - response.push_str(&String::from_utf8_lossy(&commit_output.stdout)); - if !commit_output.stderr.is_empty() { - response.push_str(&String::from_utf8_lossy(&commit_output.stderr)); - } - } - - Ok(response) -} - -pub fn git_discard_all_changes(workspace_path: &str) -> Result { - let reset_output = Command::new("git") - .current_dir(workspace_path) - .args(["reset", "--hard"]) - .output() - .map_err(|e| e.to_string())?; - - if !reset_output.status.success() { - return Err(String::from_utf8_lossy(&reset_output.stderr).to_string()); - } - - let clean_output = Command::new("git") - .current_dir(workspace_path) - .args(["clean", "-fd"]) - .output() - .map_err(|e| e.to_string())?; - - if !clean_output.status.success() { - return Err(String::from_utf8_lossy(&clean_output.stderr).to_string()); - } - - let mut response = String::new(); - response.push_str(&String::from_utf8_lossy(&reset_output.stdout)); - if !reset_output.stderr.is_empty() { - response.push_str(&String::from_utf8_lossy(&reset_output.stderr)); - } - response.push_str(&String::from_utf8_lossy(&clean_output.stdout)); - if !clean_output.stderr.is_empty() { - response.push_str(&String::from_utf8_lossy(&clean_output.stderr)); - } - - Ok(response) -} - -pub fn git_discard_files(workspace_path: &str, file_paths: Vec) -> Result { - let mut response = String::new(); - - // Get status of all files to determine which are tracked/untracked - let status_output = Command::new("git") - .current_dir(workspace_path) - .args(["status", "--porcelain"]) - .output() - .map_err(|e| e.to_string())?; - - if !status_output.status.success() { - return Err(String::from_utf8_lossy(&status_output.stderr).to_string()); - } - - let status_str = String::from_utf8_lossy(&status_output.stdout); - let mut untracked_files = Vec::new(); - let mut tracked_files = Vec::new(); - - // Parse status to categorize files - for file_path in &file_paths { - let mut is_untracked = false; - for line in status_str.lines() { - if line.len() < 4 { - continue; - } - let status_code = &line[0..2]; - let file_in_status = line[3..].trim(); - - if file_in_status == file_path { - // Check if file is untracked (status code "??") - if status_code == "??" { - is_untracked = true; - } - break; - } - } - - if is_untracked { - untracked_files.push(file_path); - } else { - tracked_files.push(file_path); - } - } - - // First, unstage any staged files (restore from HEAD to index) - if !file_paths.is_empty() { - let mut unstage_args = vec!["restore", "--staged"]; - for file_path in &file_paths { - unstage_args.push(file_path); - } - - let unstage_output = Command::new("git") - .current_dir(workspace_path) - .args(&unstage_args) - .output() - .map_err(|e| e.to_string())?; - - // Unstaging untracked files will fail, but that's okay - if unstage_output.status.success() { - response.push_str(&String::from_utf8_lossy(&unstage_output.stdout)); - } - } - - // Discard tracked files (restore working tree from index) - if !tracked_files.is_empty() { - let mut restore_args = vec!["restore"]; - for file_path in &tracked_files { - restore_args.push(file_path); - } - - let restore_output = Command::new("git") - .current_dir(workspace_path) - .args(&restore_args) - .output() - .map_err(|e| e.to_string())?; - - if !restore_output.status.success() { - return Err(String::from_utf8_lossy(&restore_output.stderr).to_string()); - } - - response.push_str(&String::from_utf8_lossy(&restore_output.stdout)); - if !restore_output.stderr.is_empty() { - response.push_str(&String::from_utf8_lossy(&restore_output.stderr)); - } - } - - // Remove untracked files - for file_path in untracked_files { - let file_full_path = std::path::Path::new(workspace_path).join(file_path); - if file_full_path.exists() { - if file_full_path.is_dir() { - std::fs::remove_dir_all(&file_full_path) - .map_err(|e| format!("Failed to remove directory {}: {}", file_path, e))?; - } else { - std::fs::remove_file(&file_full_path) - .map_err(|e| format!("Failed to remove file {}: {}", file_path, e))?; - } - response.push_str(&format!("Removed untracked file: {}\n", file_path)); - } - } - - if response.is_empty() { - response = "Files discarded successfully".to_string(); - } - - Ok(response) -} - -pub fn has_uncommitted_changes(workspace_path: &str) -> Result { - let output = Command::new("git") - .current_dir(workspace_path) - .args(["status", "--porcelain"]) - .output() - .map_err(|e| e.to_string())?; - - if output.status.success() { - Ok(!output.stdout.is_empty()) - } else { - Err(String::from_utf8_lossy(&output.stderr).to_string()) - } -} - -/// Stage all changes -pub fn git_add_all(workspace_path: &str) -> Result { - let output = Command::new("git") - .current_dir(workspace_path) - .args(["add", "."]) - .output() - .map_err(|e| e.to_string())?; - - if output.status.success() { - Ok(String::from_utf8_lossy(&output.stdout).to_string()) - } else { - Err(String::from_utf8_lossy(&output.stderr).to_string()) - } -} - -/// Unstage all staged changes -pub fn git_unstage_all(workspace_path: &str) -> Result { - let output = Command::new("git") - .current_dir(workspace_path) - .args(["reset", "HEAD"]) - .output() - .map_err(|e| e.to_string())?; - - if output.status.success() { - Ok(String::from_utf8_lossy(&output.stdout).to_string()) - } else { - Err(String::from_utf8_lossy(&output.stderr).to_string()) - } -} - -/// Push changes to remote -pub fn git_push(workspace_path: &str) -> Result { - let output = Command::new("git") - .current_dir(workspace_path) - .args(["push"]) - .output() - .map_err(|e| e.to_string())?; - - if output.status.success() { - let stdout = String::from_utf8_lossy(&output.stdout).to_string(); - let stderr = String::from_utf8_lossy(&output.stderr).to_string(); - Ok(format!("{}{}", stdout, stderr)) - } else { - Err(String::from_utf8_lossy(&output.stderr).to_string()) - } -} - -/// Force push changes to remote (use with caution) -pub fn git_push_force(workspace_path: &str) -> Result { - let output = Command::new("git") - .current_dir(workspace_path) - .args(["push", "--force"]) - .output() - .map_err(|e| e.to_string())?; - - if output.status.success() { - let stdout = String::from_utf8_lossy(&output.stdout).to_string(); - let stderr = String::from_utf8_lossy(&output.stderr).to_string(); - Ok(format!("{}{}", stdout, stderr)) - } else { - Err(String::from_utf8_lossy(&output.stderr).to_string()) - } -} - -/// Amend the last commit with a new message -pub fn git_commit_amend(workspace_path: &str, message: &str) -> Result { - let output = Command::new("git") - .current_dir(workspace_path) - .args(["commit", "--amend", "-m", message]) - .output() - .map_err(|e| e.to_string())?; - - if output.status.success() { - Ok(String::from_utf8_lossy(&output.stdout).to_string()) - } else { - Err(String::from_utf8_lossy(&output.stderr).to_string()) - } -} - -/// Pull changes from remote -pub fn git_pull(workspace_path: &str) -> Result { - let output = Command::new("git") - .current_dir(workspace_path) - .args(["pull"]) - .output() - .map_err(|e| e.to_string())?; - - if output.status.success() { - Ok(String::from_utf8_lossy(&output.stdout).to_string()) - } else { - Err(String::from_utf8_lossy(&output.stderr).to_string()) - } -} - -/// Fetch from remote -pub fn git_fetch(workspace_path: &str) -> Result { - let output = Command::new("git") - .current_dir(workspace_path) - .args(["fetch"]) - .output() - .map_err(|e| e.to_string())?; - - if output.status.success() { - Ok(String::from_utf8_lossy(&output.stdout).to_string()) - } else { - Err(String::from_utf8_lossy(&output.stderr).to_string()) - } -} - -/// Stage specific file(s) -pub fn git_stage_file(workspace_path: &str, file_path: &str) -> Result { - let output = Command::new("git") - .current_dir(workspace_path) - .args(["add", file_path]) - .output() - .map_err(|e| e.to_string())?; - - if output.status.success() { - Ok(String::from_utf8_lossy(&output.stdout).to_string()) - } else { - Err(String::from_utf8_lossy(&output.stderr).to_string()) - } -} - -/// Unstage specific file(s) -pub fn git_unstage_file(workspace_path: &str, file_path: &str) -> Result { - let output = Command::new("git") - .current_dir(workspace_path) - .args(["reset", "HEAD", file_path]) - .output() - .map_err(|e| e.to_string())?; - - if output.status.success() { - Ok(String::from_utf8_lossy(&output.stdout).to_string()) - } else { - Err(String::from_utf8_lossy(&output.stderr).to_string()) - } -} - -/// Check if a git status entry represents a directory -/// Returns true if the entry is a directory based on: -/// 1. Trailing slash in path (git's standard convention) -/// 2. Filesystem verification (fallback for edge cases) -fn is_directory_entry(workspace_path: &str, status_entry: &str) -> bool { - // Extract file path from porcelain format: "XY filename" - let path_start = if status_entry.len() > 3 { 3 } else { 0 }; - let file_path = status_entry[path_start..].trim(); - - // Git status adds '/' suffix to untracked directories - if file_path.ends_with('/') { - return true; - } - - // Fallback: check filesystem for edge cases - let full_path = std::path::Path::new(workspace_path).join(file_path); - full_path.is_dir() -} - -/// Get list of modified/untracked files (excluding .gitignore) -pub fn git_get_changed_files(workspace_path: &str) -> Result, String> { - let mut files: Vec = Vec::new(); - - // Get tracked changes (modified, added, deleted, staged) - let status_output = Command::new("git") - .current_dir(workspace_path) - .args(["status", "--porcelain"]) - .output() - .map_err(|e| e.to_string())?; - - if !status_output.status.success() { - return Err(String::from_utf8_lossy(&status_output.stderr).to_string()); - } - - let status = String::from_utf8_lossy(&status_output.stdout); - for line in status.lines() { - if line.len() > 3 { - // Filter out directory entries - only include files - if !is_directory_entry(workspace_path, line) { - // Return full porcelain format: "XY filename" - files.push(line.to_string()); - } - } - } - - // Get untracked files (individual files, respecting .gitignore) - // Prefix with "?? " to match porcelain format - let untracked_output = Command::new("git") - .current_dir(workspace_path) - .args(["ls-files", "--others", "--exclude-standard"]) - .output() - .map_err(|e| e.to_string())?; - - if untracked_output.status.success() { - let untracked = String::from_utf8_lossy(&untracked_output.stdout); - for line in untracked.lines() { - if !line.is_empty() { - // Format as porcelain: "?? filename" - files.push(format!("?? {}", line)); - } - } - } - - Ok(files) -} - -/// Get line-level diff statistics against a base branch -pub fn git_get_line_diff_stats( - workspace_path: &str, - base_branch: &str, -) -> Result { - let range = format!("{}...HEAD", base_branch); - let output = Command::new("git") - .current_dir(workspace_path) - .args(["diff", "--numstat", &range]) - .output() - .map_err(|e| e.to_string())?; - - if !output.status.success() { - return Err(String::from_utf8_lossy(&output.stderr).to_string()); - } - - let stdout = String::from_utf8_lossy(&output.stdout); - let mut lines_added: usize = 0; - let mut lines_deleted: usize = 0; - - for line in stdout.lines() { - let parts: Vec<&str> = line.split('\t').collect(); - if parts.len() >= 2 { - // Binary files show "-" instead of numbers - if parts[0] != "-" { - lines_added += parts[0].parse::().unwrap_or(0); - } - if parts[1] != "-" { - lines_deleted += parts[1].parse::().unwrap_or(0); - } - } - } - - Ok(LineDiffStats { - lines_added, - lines_deleted, - }) -} - -pub fn git_get_changed_files_between_branches( - repo_path: &str, - base_branch: &str, - head_branch: &str, -) -> Result, String> { - let range = format!("{}..{}", base_branch, head_branch); - let output = Command::new("git") - .current_dir(repo_path) - .args(["diff", "--name-status", &range]) - .output() - .map_err(|e| e.to_string())?; - - if !output.status.success() { - return Err(String::from_utf8_lossy(&output.stderr).to_string()); - } - - let stdout = String::from_utf8_lossy(&output.stdout); - let mut changes = Vec::new(); - - for line in stdout.lines() { - if line.trim().is_empty() { - continue; - } - - let mut parts = line.split('\t'); - let status_raw = parts.next().unwrap_or("").trim(); - let status = status_raw.chars().next().unwrap_or('M').to_string(); - let remaining: Vec<&str> = parts.collect(); - - let (path, previous_path) = match remaining.as_slice() { - [] => (String::new(), None), - [single] => (single.trim().to_string(), None), - [old_path, new_path] => ( - new_path.trim().to_string(), - Some(old_path.trim().to_string()), - ), - _ => { - let last = remaining.last().unwrap().trim().to_string(); - (last, None) - } - }; - - if path.is_empty() { - continue; - } - - changes.push(BranchDiffFileChange { - path, - previous_path, - status, - }); - } - - Ok(changes) -} - -pub fn git_get_diff_between_branches( - repo_path: &str, - base_branch: &str, - head_branch: &str, -) -> Result, String> { - let range = format!("{}..{}", base_branch, head_branch); - let changes = git_get_changed_files_between_branches(repo_path, base_branch, head_branch)?; - let mut status_map: HashMap = HashMap::new(); - for change in changes.into_iter() { - if let Some(prev) = &change.previous_path { - status_map.insert(prev.clone(), change.clone()); - } - status_map.insert(change.path.clone(), change); - } - - let output = Command::new("git") - .current_dir(repo_path) - .args(["diff", "--unified=200", "--no-color", &range]) - .output() - .map_err(|e| e.to_string())?; - - if !output.status.success() { - return Err(String::from_utf8_lossy(&output.stderr).to_string()); - } - - let diff_text = String::from_utf8_lossy(&output.stdout); - Ok(parse_branch_diff(&diff_text, &status_map)) -} - -pub fn git_get_commits_between_branches( - repo_path: &str, - base_branch: &str, - head_branch: &str, - limit: Option, -) -> Result, String> { - let range = format!("{}..{}", base_branch, head_branch); - let max_count = limit.unwrap_or(50); - let format = "%H\x1f%h\x1f%an\x1f%ae\x1f%ad\x1f%s\x1e"; - - let output = Command::new("git") - .current_dir(repo_path) - .args([ - "log", - &format!("--max-count={}", max_count), - "--date=iso-strict", - &format!("--pretty=format:{}", format), - &range, - ]) - .output() - .map_err(|e| e.to_string())?; - - if !output.status.success() { - return Err(String::from_utf8_lossy(&output.stderr).to_string()); - } - - let stdout = String::from_utf8_lossy(&output.stdout); - let mut commits = Vec::new(); - for record in stdout.split('\x1e') { - if record.trim().is_empty() { - continue; - } - let mut fields = record.split('\x1f'); - let hash = fields.next().unwrap_or("").trim(); - if hash.is_empty() { - continue; - } - let abbreviated_hash = fields.next().unwrap_or("").trim().to_string(); - let author_name = fields.next().unwrap_or("").trim().to_string(); - let author_email = fields.next().unwrap_or("").trim().to_string(); - let date = fields.next().unwrap_or("").trim().to_string(); - let message = fields.next().unwrap_or("").trim().to_string(); - - commits.push(BranchCommitInfo { - hash: hash.to_string(), - abbreviated_hash, - author_name, - author_email, - date, - message, - }); - } - - Ok(commits) -} - -pub fn git_stage_hunk(workspace_path: &str, patch: &str) -> Result { - apply_patch(workspace_path, patch, false) -} - -pub fn git_unstage_hunk(workspace_path: &str, patch: &str) -> Result { - apply_patch(workspace_path, patch, true) -} - -/// Represents a line selection for staging -#[derive(Debug, serde::Deserialize)] -pub struct LineSelection { - /// The hunk index this line belongs to - pub hunk_index: usize, - /// The line index within the hunk - pub line_index: usize, - /// The line content (including +/- prefix) - #[allow(dead_code)] - pub content: String, -} - -/// Stage selected lines from multiple hunks -/// This builds a custom patch containing only the selected changed lines with proper context -pub fn git_stage_selected_lines( - workspace_path: &str, - file_path: &str, - selections: Vec, - metadata_lines: Vec, - hunks: Vec<(String, Vec)>, // (header, lines) for each hunk -) -> Result { - let patch = build_selected_lines_patch(file_path, &metadata_lines, &hunks, &selections, false)?; - apply_patch(workspace_path, &patch, false) -} - -/// Unstage selected lines -pub fn git_unstage_selected_lines( - workspace_path: &str, - file_path: &str, - selections: Vec, - metadata_lines: Vec, - hunks: Vec<(String, Vec)>, -) -> Result { - let patch = build_selected_lines_patch(file_path, &metadata_lines, &hunks, &selections, true)?; - apply_patch(workspace_path, &patch, true) -} - -/// Build a patch containing only the selected changed lines with proper context -fn build_selected_lines_patch( - file_path: &str, - metadata_lines: &[String], - hunks: &[(String, Vec)], - selections: &[LineSelection], - _for_unstage: bool, -) -> Result { - if selections.is_empty() { - return Err("No lines selected".to_string()); - } - - // Group selections by hunk - let mut selections_by_hunk: std::collections::HashMap> = - std::collections::HashMap::new(); - for sel in selections { - selections_by_hunk - .entry(sel.hunk_index) - .or_default() - .push(sel); - } - - let mut patch_parts: Vec = Vec::new(); - - // Add metadata - let mut has_diff = false; - let mut has_old = false; - let mut has_new = false; - - for line in metadata_lines { - if line.starts_with("diff --git") { - has_diff = true; - patch_parts.push(line.clone()); - } else if line.starts_with("index ") - || line.starts_with("old mode") - || line.starts_with("new mode") - || line.starts_with("deleted file mode") - || line.starts_with("new file mode") - || line.starts_with("similarity index") - || line.starts_with("rename from") - || line.starts_with("rename to") - { - patch_parts.push(line.clone()); - } else if line.starts_with("--- ") { - has_old = true; - patch_parts.push(line.clone()); - } else if line.starts_with("+++ ") { - has_new = true; - patch_parts.push(line.clone()); - } - } - - if !has_diff { - patch_parts.push(format!("diff --git a/{0} b/{0}", file_path)); - } - if !has_old { - patch_parts.push(format!("--- a/{}", file_path)); - } - if !has_new { - patch_parts.push(format!("+++ b/{}", file_path)); - } - - // Process each hunk that has selections - for (hunk_idx, (header, lines)) in hunks.iter().enumerate() { - let Some(hunk_selections) = selections_by_hunk.get(&hunk_idx) else { - continue; - }; - - // Parse the original hunk header to get starting line numbers - let (old_start, new_start) = parse_hunk_header(header); - - // Build the new hunk with only selected changes - let mut new_hunk_lines: Vec = Vec::new(); - let mut old_count = 0usize; - let mut new_count = 0usize; - - // Get the set of selected line indices - let selected_indices: std::collections::HashSet = - hunk_selections.iter().map(|s| s.line_index).collect(); - - for (line_idx, line) in lines.iter().enumerate() { - let first_char = line.chars().next().unwrap_or(' '); - - match first_char { - '+' => { - if selected_indices.contains(&line_idx) { - // Include this addition - new_hunk_lines.push(line.clone()); - new_count += 1; - } - // If not selected, we skip it (don't add to new file) - } - '-' => { - if selected_indices.contains(&line_idx) { - // Include this deletion - new_hunk_lines.push(line.clone()); - old_count += 1; - } else { - // Convert unselected deletion to context line - let content = line.get(1..).unwrap_or(""); - new_hunk_lines.push(format!(" {}", content)); - old_count += 1; - new_count += 1; - } - } - ' ' | _ => { - // Context line - always include - new_hunk_lines.push(line.clone()); - old_count += 1; - new_count += 1; - } - } - } - - // Only add the hunk if it has actual changes - let has_changes = new_hunk_lines - .iter() - .any(|l| l.starts_with('+') || l.starts_with('-')); - - if has_changes { - // Create new header with updated counts - let new_header = format!( - "@@ -{},{} +{},{} @@", - old_start, old_count, new_start, new_count - ); - patch_parts.push(new_header); - patch_parts.extend(new_hunk_lines); - } - } - - patch_parts.push(String::new()); - Ok(patch_parts.join("\n")) -} - -pub fn git_get_file_hunks(workspace_path: &str, file_path: &str) -> Result, String> { - let staged_diff = git_diff_for_file(workspace_path, file_path, true)?; - let unstaged_diff = git_diff_for_file(workspace_path, file_path, false)?; - - let mut hunks = Vec::new(); - hunks.extend(parse_diff_hunks(&staged_diff, file_path, true, "staged", 0)); - let next_index = hunks.len(); - hunks.extend(parse_diff_hunks( - &unstaged_diff, - file_path, - false, - "unstaged", - next_index, - )); - - Ok(hunks) -} - -fn git_diff_for_file(workspace_path: &str, file_path: &str, staged: bool) -> Result { - let mut cmd = Command::new("git"); - cmd.current_dir(workspace_path) - .arg("diff") - .arg("--unified=3"); - - if staged { - cmd.arg("--cached"); - } - - let output = cmd - .arg("--") - .arg(file_path) - .output() - .map_err(|e| e.to_string())?; - - if output.status.success() { - Ok(String::from_utf8_lossy(&output.stdout).to_string()) - } else { - Err(String::from_utf8_lossy(&output.stderr).to_string()) - } -} - -fn parse_diff_hunks( - diff: &str, - file_path: &str, - is_staged: bool, - prefix: &str, - start_index: usize, -) -> Vec { - if diff.trim().is_empty() { - return Vec::new(); - } - - let mut metadata_lines: Vec = Vec::new(); - let mut in_hunk = false; - let mut current_header = String::new(); - let mut current_lines: Vec = Vec::new(); - let mut hunks: Vec = Vec::new(); - let mut counter = start_index; - - for line in diff.lines() { - if line.starts_with("@@") { - if !current_header.is_empty() { - push_hunk_entry( - &mut hunks, - file_path, - &metadata_lines, - ¤t_header, - ¤t_lines, - is_staged, - prefix, - counter, - ); - counter += 1; - } - current_header = line.to_string(); - current_lines = vec![line.to_string()]; - in_hunk = true; - } else if in_hunk { - current_lines.push(line.to_string()); - } else { - metadata_lines.push(line.to_string()); - } - } - - if !current_header.is_empty() { - push_hunk_entry( - &mut hunks, - file_path, - &metadata_lines, - ¤t_header, - ¤t_lines, - is_staged, - prefix, - counter, - ); - } - - hunks -} - -fn push_hunk_entry( - hunks: &mut Vec, - file_path: &str, - metadata_lines: &[String], - header: &str, - lines: &[String], - is_staged: bool, - prefix: &str, - index: usize, -) { - if header.is_empty() || lines.is_empty() { - return; - } - - let display_lines = if lines.len() > 1 { - lines[1..].to_vec() - } else { - Vec::new() - }; - - let patch = build_patch(file_path, metadata_lines, lines); - hunks.push(DiffHunk { - id: format!("{}-{}", prefix, index), - header: header.to_string(), - lines: display_lines, - is_staged, - patch, - }); -} - -fn build_patch(file_path: &str, metadata_lines: &[String], hunk_lines: &[String]) -> String { - let mut patch_parts: Vec = Vec::new(); - - let mut has_diff = false; - let mut has_old = false; - let mut has_new = false; - - for line in metadata_lines { - if line.starts_with("diff --git") { - has_diff = true; - patch_parts.push(line.clone()); - } else if line.starts_with("index ") - || line.starts_with("old mode") - || line.starts_with("new mode") - || line.starts_with("deleted file mode") - || line.starts_with("new file mode") - || line.starts_with("similarity index") - || line.starts_with("rename from") - || line.starts_with("rename to") - { - patch_parts.push(line.clone()); - } else if line.starts_with("--- ") { - has_old = true; - patch_parts.push(line.clone()); - } else if line.starts_with("+++ ") { - has_new = true; - patch_parts.push(line.clone()); - } - } - - if !has_diff { - patch_parts.push(format!("diff --git a/{0} b/{0}", file_path)); - } - if !has_old { - patch_parts.push(format!("--- a/{}", file_path)); - } - if !has_new { - patch_parts.push(format!("+++ b/{}", file_path)); - } - - patch_parts.extend(hunk_lines.iter().cloned()); - patch_parts.push(String::new()); - patch_parts.join("\n") -} - -fn apply_patch(workspace_path: &str, patch: &str, reverse: bool) -> Result { - let mut cmd = Command::new("git"); - cmd.current_dir(workspace_path).arg("apply").arg("--cached"); - - if reverse { - cmd.arg("--reverse"); - } - - let mut child = cmd - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn() - .map_err(|e| e.to_string())?; - - { - let stdin = child - .stdin - .as_mut() - .ok_or_else(|| "Failed to open git apply stdin".to_string())?; - stdin - .write_all(patch.as_bytes()) - .map_err(|e| e.to_string())?; - } - - let output = child.wait_with_output().map_err(|e| e.to_string())?; - - if output.status.success() { - Ok(String::from_utf8_lossy(&output.stdout).to_string()) - } else { - Err(String::from_utf8_lossy(&output.stderr).to_string()) - } -} - -fn parse_branch_diff( - diff_text: &str, - status_map: &HashMap, -) -> Vec { - fn normalize_diff_path(token: &str) -> String { - let trimmed = token.trim().trim_matches('"'); - if let Some(stripped) = trimmed.strip_prefix("a/") { - stripped.to_string() - } else if let Some(stripped) = trimmed.strip_prefix("b/") { - stripped.to_string() - } else { - trimmed.to_string() - } - } - - let mut files = Vec::new(); - let mut current_file: Option = None; - let mut current_hunk: Option = None; - let mut old_line = 0usize; - let mut new_line = 0usize; - - let finalize_current_file = - |current_file: &mut Option, - current_hunk: &mut Option, - files: &mut Vec| { - if let Some(mut file) = current_file.take() { - if let Some(hunk) = current_hunk.take() { - file.hunks.push(hunk); - } - files.push(file); - } - }; - - for line in diff_text.lines() { - if line.starts_with("diff --git ") { - finalize_current_file(&mut current_file, &mut current_hunk, &mut files); - - let mut parts = line.split_whitespace().skip(2); - let old_token = parts.next().unwrap_or(""); - let new_token = parts.next().unwrap_or(""); - let old_path = normalize_diff_path(old_token); - let mut path = normalize_diff_path(new_token); - if path.is_empty() { - path = old_path.clone(); - } - - let mut file_diff = BranchDiffFileDiff { - path: path.clone(), - previous_path: None, - status: "M".to_string(), - is_binary: false, - binary_message: None, - metadata: Vec::new(), - hunks: Vec::new(), - }; - - if let Some(change) = status_map.get(&file_diff.path) { - file_diff.status = change.status.clone(); - file_diff.previous_path = change.previous_path.clone(); - } else if let Some(change) = status_map.get(&old_path) { - file_diff.status = change.status.clone(); - file_diff.previous_path = change - .previous_path - .clone() - .or_else(|| Some(old_path.clone())); - } - - current_file = Some(file_diff); - current_hunk = None; - continue; - } - - if let Some(ref mut file) = current_file { - if line.starts_with("@@") { - if let Some(hunk) = current_hunk.take() { - file.hunks.push(hunk); - } - let (old_start, new_start) = parse_hunk_header(line); - old_line = old_start; - new_line = new_start; - current_hunk = Some(BranchDiffHunk { - header: line.to_string(), - lines: Vec::new(), - }); - continue; - } - - if line.starts_with("--- ") { - file.metadata.push(line.to_string()); - continue; - } - - if line.starts_with("+++ ") { - file.metadata.push(line.to_string()); - let new_token = line.trim_start_matches("+++ ").trim(); - if new_token != "/dev/null" { - let normalized = normalize_diff_path(new_token); - if !normalized.is_empty() { - file.path = normalized.clone(); - if let Some(change) = status_map.get(&file.path) { - file.status = change.status.clone(); - file.previous_path = change.previous_path.clone(); - } - } - } - continue; - } - - if line.starts_with("rename from ") { - file.metadata.push(line.to_string()); - let prev = line.trim_start_matches("rename from ").trim().to_string(); - if !prev.is_empty() { - file.previous_path = Some(prev); - } - continue; - } - - if line.starts_with("rename to ") { - file.metadata.push(line.to_string()); - let new_name = line.trim_start_matches("rename to ").trim().to_string(); - if !new_name.is_empty() { - file.path = new_name; - } - continue; - } - - if line.starts_with("new file mode") - || line.starts_with("deleted file mode") - || line.starts_with("index ") - || line.starts_with("similarity index") - || line.starts_with("old mode") - || line.starts_with("new mode") - { - file.metadata.push(line.to_string()); - continue; - } - - if line.starts_with("Binary files") || line.starts_with("GIT binary patch") { - file.is_binary = true; - if file.binary_message.is_none() { - file.binary_message = Some(line.to_string()); - } - file.metadata.push(line.to_string()); - continue; - } - - if let Some(ref mut hunk) = current_hunk { - if line.starts_with('\\') { - hunk.lines.push(BranchDiffLine { - content: line.to_string(), - kind: DiffLineKind::Meta, - old_line: None, - new_line: None, - }); - continue; - } - - if let Some(first_char) = line.chars().next() { - match first_char { - '+' => { - let content = line.get(1..).unwrap_or("").to_string(); - hunk.lines.push(BranchDiffLine { - content, - kind: DiffLineKind::Addition, - old_line: None, - new_line: Some(new_line), - }); - new_line = new_line.saturating_add(1); - } - '-' => { - let content = line.get(1..).unwrap_or("").to_string(); - hunk.lines.push(BranchDiffLine { - content, - kind: DiffLineKind::Deletion, - old_line: Some(old_line), - new_line: None, - }); - old_line = old_line.saturating_add(1); - } - ' ' => { - let content = line.get(1..).unwrap_or("").to_string(); - hunk.lines.push(BranchDiffLine { - content, - kind: DiffLineKind::Context, - old_line: Some(old_line), - new_line: Some(new_line), - }); - old_line = old_line.saturating_add(1); - new_line = new_line.saturating_add(1); - } - _ => { - hunk.lines.push(BranchDiffLine { - content: line.to_string(), - kind: DiffLineKind::Meta, - old_line: None, - new_line: None, - }); - } - } - } - } - } - } - - finalize_current_file(&mut current_file, &mut current_hunk, &mut files); - files -} - -fn parse_hunk_header(header: &str) -> (usize, usize) { - let mut old_start = 0usize; - let mut new_start = 0usize; - let parts: Vec<&str> = header.split_whitespace().collect(); - if parts.len() >= 3 { - old_start = parts[1] - .trim_start_matches('-') - .split(',') - .next() - .unwrap_or("0") - .parse() - .unwrap_or(0); - new_start = parts[2] - .trim_start_matches('+') - .split(',') - .next() - .unwrap_or("0") - .parse() - .unwrap_or(0); - } - (old_start, new_start) -} - -/// Get specific lines from a file (for expanding context in diffs) -pub fn git_get_file_lines( - workspace_path: &str, - file_path: &str, - is_staged: bool, - start_line: usize, - end_line: usize, -) -> Result { - let lines = if is_staged { - // Get staged version using git show - let output = Command::new("git") - .current_dir(workspace_path) - .args(["show", &format!(":0:{}", file_path)]) - .output() - .map_err(|e| format!("Failed to execute git show: {}", e))?; - - if !output.status.success() { - return Err(String::from_utf8_lossy(&output.stderr).to_string()); - } - - String::from_utf8_lossy(&output.stdout).to_string() - } else { - // Get working directory version - let full_path = format!("{}/{}", workspace_path, file_path); - std::fs::read_to_string(&full_path) - .map_err(|e| format!("Failed to read file: {}", e))? - }; - - let all_lines: Vec = lines.lines().map(|s| s.to_string()).collect(); - - // Extract requested range (1-indexed) - let start_idx = start_line.saturating_sub(1); - let end_idx = end_line.min(all_lines.len()); - - if start_idx >= all_lines.len() { - return Ok(FileLines { - lines: Vec::new(), - start_line, - end_line: start_line, - }); - } - - let extracted_lines = all_lines[start_idx..end_idx].to_vec(); - let line_count = extracted_lines.len(); - - Ok(FileLines { - lines: extracted_lines, - start_line, - end_line: start_idx + line_count, - }) -} diff --git a/src-tauri/src/jj.rs b/src-tauri/src/jj.rs index 5743c4ab..2d18fc02 100644 --- a/src-tauri/src/jj.rs +++ b/src-tauri/src/jj.rs @@ -29,6 +29,40 @@ pub struct WorkspaceInfo { pub is_colocated: bool, } +/// A diff hunk from jj diff output +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct JjDiffHunk { + pub id: String, + pub header: String, + pub lines: Vec, + pub patch: String, +} + +/// File change status in JJ working copy +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct JjFileChange { + pub path: String, + pub status: String, + pub previous_path: Option, +} + +/// File content lines for context expansion +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct JjFileLines { + pub lines: Vec, + pub start_line: usize, + pub end_line: usize, +} + +/// Result of a rebase operation +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct JjRebaseResult { + pub success: bool, + pub message: String, + pub has_conflicts: bool, + pub conflicted_files: Vec, +} + impl std::fmt::Display for JjError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -286,21 +320,33 @@ pub fn create_workspace( let workspace_path_str = workspace_dir.to_string_lossy().to_string(); - // Create git workspace first - crate::git::create_workspace_at_path( - repo_path, - branch_name, - new_branch, - source_branch, - &workspace_path_str, - ) - .map_err(JjError::GitWorkspaceError)?; - - // Copy selected ignored files - if let Some(patterns) = inclusion_patterns { - if let Err(e) = crate::git::copy_ignored_files(repo_path, &workspace_path_str, patterns) { - eprintln!("Warning: Failed to copy ignored files: {}", e); - } + // Create git workspace first using git worktree command + let mut git_cmd = std::process::Command::new("git"); + git_cmd.current_dir(repo_path) + .arg("worktree") + .arg("add"); + + if new_branch { + git_cmd.arg("-b").arg(branch_name); + } else { + git_cmd.arg("--no-track"); + } + + git_cmd.arg(&workspace_path_str); + + if let Some(source) = source_branch { + git_cmd.arg(source); + } else if !new_branch { + git_cmd.arg(branch_name); + } + + let output = git_cmd.output() + .map_err(|e| JjError::GitWorkspaceError(format!("Failed to execute git worktree: {}", e)))?; + + if !output.status.success() { + return Err(JjError::GitWorkspaceError( + String::from_utf8_lossy(&output.stderr).to_string() + )); } // Initialize jj for this workspace (colocated mode) @@ -311,7 +357,10 @@ pub fn create_workspace( if let Err(e) = jj_result { // Clean up: remove the git workspace we just created - let _ = crate::git::remove_workspace(repo_path, &workspace_path_str); + let _ = std::process::Command::new("git") + .current_dir(repo_path) + .args(&["worktree", "remove", "--force", &workspace_path_str]) + .output(); let _ = fs::remove_dir_all(&workspace_dir); return Err(JjError::InitFailed(format!( "Failed to init jj workspace: {}", @@ -319,6 +368,12 @@ pub fn create_workspace( ))); } + // Create initial bookmark pointing at current working copy + if let Err(e) = jj_set_bookmark(&workspace_path_str, branch_name, "@") { + eprintln!("Warning: Failed to create initial bookmark '{}': {}", branch_name, e); + // Don't fail workspace creation for bookmark errors + } + Ok(workspace_path_str) } @@ -406,9 +461,18 @@ pub fn remove_workspace( return Err(JjError::WorkspaceNotFound(workspace_path.to_string())); } - // Remove git workspace first - crate::git::remove_workspace(repo_path, workspace_path) - .map_err(JjError::GitWorkspaceError)?; + // Remove git workspace first using git worktree command + let output = std::process::Command::new("git") + .current_dir(repo_path) + .args(&["worktree", "remove", "--force", workspace_path]) + .output() + .map_err(|e| JjError::GitWorkspaceError(format!("Failed to execute git worktree remove: {}", e)))?; + + if !output.status.success() { + return Err(JjError::GitWorkspaceError( + String::from_utf8_lossy(&output.stderr).to_string() + )); + } // Remove directory if it still exists (git worktree remove command should handle this) if workspace_dir.exists() { @@ -441,3 +505,484 @@ pub fn get_workspace_info(workspace_path: &str) -> Result@ +pub fn squash_to_workspace( + source_workspace_path: &str, + target_workspace_name: &str, + file_paths: Option>, +) -> Result { + // Construct the target revision reference: workspace-name@ + let target_ref = format!("{}@", target_workspace_name); + + // Build the jj squash command + let mut cmd = Command::new("jj"); + cmd.current_dir(source_workspace_path); + cmd.args(["squash", "--from", "@", "--into", &target_ref]); + + // If specific file paths are provided, add them + if let Some(paths) = file_paths { + if !paths.is_empty() { + for path in paths { + cmd.arg(path); + } + } + } + + let output = cmd.output().map_err(|e| JjError::IoError(e.to_string()))?; + + if output.status.success() { + Ok(String::from_utf8_lossy(&output.stdout).to_string()) + } else { + Err(JjError::InitFailed(format!( + "Failed to squash changes: {}", + String::from_utf8_lossy(&output.stderr) + ))) + } +} + +// ============================================================================ +// Diff Operations using hybrid CLI approach +// Uses jj CLI for file listing (faster) and git CLI for diffs (reliable) +// ============================================================================ + +/// Get list of changed files in working copy using jj status +/// This is faster than git status for large repos +pub fn jj_get_changed_files(workspace_path: &str) -> Result, JjError> { + let output = Command::new("jj") + .current_dir(workspace_path) + .args(["status", "--no-pager"]) + .output() + .map_err(|e| JjError::IoError(e.to_string()))?; + + if !output.status.success() { + return Err(JjError::IoError( + String::from_utf8_lossy(&output.stderr).to_string(), + )); + } + + let status_output = String::from_utf8_lossy(&output.stdout); + parse_jj_status(&status_output) +} + +/// Parse jj status output into file changes +fn parse_jj_status(status: &str) -> Result, JjError> { + let mut changes = Vec::new(); + + for line in status.lines() { + let line = line.trim(); + + // Skip empty lines and section headers + if line.is_empty() || line.starts_with("Working copy") || line.starts_with("Parent commit") { + continue; + } + + // Parse lines like "M file.txt" or "A new.txt" or "D removed.txt" + if let Some((status_char, rest)) = line.split_once(' ') { + let status = match status_char { + "M" => "M", // Modified + "A" => "A", // Added + "D" => "D", // Deleted + "R" => "M", // Renamed (treat as modified for now) + _ => continue, + }; + + let path = rest.trim().to_string(); + changes.push(JjFileChange { + path, + status: status.to_string(), + previous_path: None, + }); + } + } + + Ok(changes) +} + +/// Get diff hunks for a specific file +/// Uses jj diff CLI with git-format output +pub fn jj_get_file_hunks(workspace_path: &str, file_path: &str) -> Result, JjError> { + // Use jj diff --git to get hunks in git-compatible format + let output = Command::new("jj") + .current_dir(workspace_path) + .args(["diff", "--git", "--no-pager", "--", file_path]) + .output() + .map_err(|e| JjError::IoError(e.to_string()))?; + + if !output.status.success() { + return Err(JjError::IoError( + String::from_utf8_lossy(&output.stderr).to_string(), + )); + } + + let diff_output = String::from_utf8_lossy(&output.stdout); + parse_git_diff_hunks(&diff_output) +} + +/// Parse git diff output into hunks +fn parse_git_diff_hunks(diff: &str) -> Result, JjError> { + let mut hunks = Vec::new(); + let mut current_hunk: Option<(String, Vec)> = None; + let mut hunk_index = 0; + + for line in diff.lines() { + if line.starts_with("@@") { + // Save previous hunk if exists + if let Some((header, lines)) = current_hunk.take() { + hunks.push(JjDiffHunk { + id: format!("hunk-{}", hunk_index), + header: header.clone(), + lines: lines.clone(), + patch: format!("{}\n{}", header, lines.join("\n")), + }); + hunk_index += 1; + } + + // Start new hunk + current_hunk = Some((line.to_string(), Vec::new())); + } else if let Some((_, ref mut lines)) = current_hunk { + // Skip diff metadata lines + if !line.starts_with("diff") && !line.starts_with("index") && !line.starts_with("---") && !line.starts_with("+++") { + lines.push(line.to_string()); + } + } + } + + // Save last hunk + if let Some((header, lines)) = current_hunk { + hunks.push(JjDiffHunk { + id: format!("hunk-{}", hunk_index), + header: header.clone(), + lines: lines.clone(), + patch: format!("{}\n{}", header, lines.join("\n")), + }); + } + + Ok(hunks) +} + +/// Get file content at specific lines for context expansion +pub fn jj_get_file_lines( + workspace_path: &str, + file_path: &str, + from_parent: bool, + start_line: usize, + end_line: usize, +) -> Result { + let content = if from_parent { + // Get file from parent commit using git show + let output = Command::new("git") + .current_dir(workspace_path) + .args(["show", &format!("HEAD:{}", file_path)]) + .output() + .map_err(|e| JjError::IoError(e.to_string()))?; + + if !output.status.success() { + return Err(JjError::IoError( + String::from_utf8_lossy(&output.stderr).to_string(), + )); + } + + String::from_utf8_lossy(&output.stdout).to_string() + } else { + // Read file from working directory + let full_path = Path::new(workspace_path).join(file_path); + fs::read_to_string(&full_path) + .map_err(|e| JjError::IoError(format!("Failed to read file: {}", e)))? + }; + + let all_lines: Vec<&str> = content.lines().collect(); + let start_idx = start_line.saturating_sub(1).min(all_lines.len()); + let end_idx = end_line.min(all_lines.len()); + + let lines: Vec = all_lines[start_idx..end_idx] + .iter() + .map(|s| s.to_string()) + .collect(); + + Ok(JjFileLines { + lines, + start_line: start_idx + 1, + end_line: end_idx, + }) +} + +// ============================================================================ +// Mutation Operations (CLI fallbacks) +// ============================================================================ + +/// Restore a file to parent state (discard changes) +/// Uses CLI as jj-lib mutation APIs are complex +pub fn jj_restore_file(workspace_path: &str, file_path: &str) -> Result { + let output = Command::new("jj") + .current_dir(workspace_path) + .args(["restore", file_path]) + .output() + .map_err(|e| JjError::IoError(e.to_string()))?; + + if !output.status.success() { + return Err(JjError::IoError( + String::from_utf8_lossy(&output.stderr).to_string(), + )); + } + + Ok(String::from_utf8_lossy(&output.stdout).to_string()) +} + +/// Restore all changes +pub fn jj_restore_all(workspace_path: &str) -> Result { + let output = Command::new("jj") + .current_dir(workspace_path) + .args(["restore"]) + .output() + .map_err(|e| JjError::IoError(e.to_string()))?; + + if !output.status.success() { + return Err(JjError::IoError( + String::from_utf8_lossy(&output.stderr).to_string(), + )); + } + + Ok(String::from_utf8_lossy(&output.stdout).to_string()) +} + +/// Set (or create) a jj bookmark to point at a specific revision +/// Uses: jj bookmark set -r +pub fn jj_set_bookmark(workspace_path: &str, bookmark_name: &str, revision: &str) -> Result<(), JjError> { + let output = Command::new("jj") + .current_dir(workspace_path) + .args(["bookmark", "set", bookmark_name, "-r", revision]) + .output() + .map_err(|e| JjError::IoError(e.to_string()))?; + + if !output.status.success() { + return Err(JjError::IoError( + String::from_utf8_lossy(&output.stderr).to_string(), + )); + } + + Ok(()) +} + +/// Describe and create new commit +pub fn jj_commit(workspace_path: &str, message: &str) -> Result { + // First describe + let describe = Command::new("jj") + .current_dir(workspace_path) + .args(["describe", "-m", message]) + .output() + .map_err(|e| JjError::IoError(e.to_string()))?; + + if !describe.status.success() { + return Err(JjError::IoError( + String::from_utf8_lossy(&describe.stderr).to_string(), + )); + } + + // Then create new empty commit + let new_commit = Command::new("jj") + .current_dir(workspace_path) + .args(["new"]) + .output() + .map_err(|e| JjError::IoError(e.to_string()))?; + + if !new_commit.status.success() { + return Err(JjError::IoError( + String::from_utf8_lossy(&new_commit.stderr).to_string(), + )); + } + + // Advance the bookmark to the new commit (@- is the parent, which has the content) + // Get the branch name from git (this is the bookmark name) + if let Ok(branch_name) = get_workspace_branch(workspace_path) { + if !branch_name.is_empty() && branch_name != "HEAD" { + // Set the bookmark to point at @- (the commit with the actual content) + if let Err(e) = jj_set_bookmark(workspace_path, &branch_name, "@-") { + eprintln!("Warning: Failed to advance bookmark '{}': {}", branch_name, e); + // Don't fail the commit for bookmark errors + } + } + } + + Ok("Committed successfully".to_string()) +} + +/// Rebase the current workspace onto a target branch +/// Uses: jj rebase -d +pub fn jj_rebase_onto( + workspace_path: &str, + target_branch: &str, +) -> Result { + let output = Command::new("jj") + .current_dir(workspace_path) + .args(["rebase", "-d", target_branch]) + .output() + .map_err(|e| JjError::IoError(e.to_string()))?; + + let stdout = String::from_utf8_lossy(&output.stdout); + let stderr = String::from_utf8_lossy(&output.stderr); + let combined_message = format!("{}{}", stdout, stderr); + + // Check for conflicts in output + let has_conflicts = combined_message.to_lowercase().contains("conflict"); + + // Get conflicted files if there are conflicts + let conflicted_files = if has_conflicts { + get_conflicted_files(workspace_path).unwrap_or_default() + } else { + Vec::new() + }; + + Ok(JjRebaseResult { + success: output.status.success(), + message: combined_message, + has_conflicts, + conflicted_files, + }) +} + +/// Get list of conflicted files from jj status +pub fn get_conflicted_files(workspace_path: &str) -> Result, JjError> { + let output = Command::new("jj") + .current_dir(workspace_path) + .args(["status", "--no-pager"]) + .output() + .map_err(|e| JjError::IoError(e.to_string()))?; + + if !output.status.success() { + return Ok(Vec::new()); + } + + let status = String::from_utf8_lossy(&output.stdout); + parse_conflicted_files(&status) +} + +/// Parse jj status output to extract conflicted files +/// JJ shows conflicts with "C" prefix in status output +fn parse_conflicted_files(status: &str) -> Result, JjError> { + let mut conflicts = Vec::new(); + + for line in status.lines() { + let trimmed = line.trim(); + + // Look for lines that start with "C " indicating conflicts + if let Some(rest) = trimmed.strip_prefix("C ") { + conflicts.push(rest.trim().to_string()); + } + // Also check for explicit conflict messages + else if trimmed.contains("conflict") && trimmed.contains(":") { + if let Some(file_path) = trimmed.split(':').next() { + let clean_path = file_path.trim(); + if !clean_path.is_empty() && !conflicts.contains(&clean_path.to_string()) { + conflicts.push(clean_path.to_string()); + } + } + } + } + + Ok(conflicts) +} + +/// Get the default branch of the repository (main/master) +/// Checks git symbolic-ref for origin/HEAD, falls back to checking for main/master +pub fn get_default_branch(repo_path: &str) -> Result { + // Try origin/HEAD first + let output = Command::new("git") + .current_dir(repo_path) + .args(["symbolic-ref", "refs/remotes/origin/HEAD"]) + .output() + .map_err(|e| JjError::IoError(e.to_string()))?; + + if output.status.success() { + let branch = String::from_utf8_lossy(&output.stdout) + .trim() + .strip_prefix("refs/remotes/origin/") + .unwrap_or("main") + .to_string(); + return Ok(branch); + } + + // Fallback: check for main or master branches + for branch in &["main", "master"] { + let check = Command::new("git") + .current_dir(repo_path) + .args(["rev-parse", "--verify", branch]) + .output(); + + if check.map(|o| o.status.success()).unwrap_or(false) { + return Ok(branch.to_string()); + } + } + + // Default fallback + Ok("main".to_string()) +} + +/// Push changes to remote using jj git push +pub fn jj_push(workspace_path: &str) -> Result { + let output = Command::new("jj") + .current_dir(workspace_path) + .args(["git", "push"]) + .output() + .map_err(|e| JjError::IoError(e.to_string()))?; + + let stdout = String::from_utf8_lossy(&output.stdout); + let stderr = String::from_utf8_lossy(&output.stderr); + + if !output.status.success() { + return Err(JjError::IoError(format!("{}{}", stdout, stderr))); + } + + Ok(format!("{}{}", stdout, stderr)) +} + +/// Pull changes from remote using jj git fetch + rebase +/// Fetches from origin and rebases current workspace onto tracking branch +pub fn jj_pull(workspace_path: &str) -> Result { + // First, fetch from remote + let fetch_output = Command::new("jj") + .current_dir(workspace_path) + .args(["git", "fetch"]) + .output() + .map_err(|e| JjError::IoError(e.to_string()))?; + + let fetch_stdout = String::from_utf8_lossy(&fetch_output.stdout); + let fetch_stderr = String::from_utf8_lossy(&fetch_output.stderr); + + if !fetch_output.status.success() { + return Err(JjError::IoError(format!("{}{}", fetch_stdout, fetch_stderr))); + } + + // Get the current branch name to determine tracking branch + let branch_name = get_workspace_branch(workspace_path)?; + + if branch_name.is_empty() || branch_name == "HEAD" { + // No branch - just return fetch result + return Ok(format!("{}{}", fetch_stdout, fetch_stderr)); + } + + // Rebase onto the tracking branch (branch@origin) + let tracking_branch = format!("{}@origin", branch_name); + let rebase_output = Command::new("jj") + .current_dir(workspace_path) + .args(["rebase", "-d", &tracking_branch]) + .output() + .map_err(|e| JjError::IoError(e.to_string()))?; + + let rebase_stdout = String::from_utf8_lossy(&rebase_output.stdout); + let rebase_stderr = String::from_utf8_lossy(&rebase_output.stderr); + + // Combine fetch and rebase output + let combined = format!( + "Fetch:\n{}{}\nRebase:\n{}{}", + fetch_stdout, fetch_stderr, rebase_stdout, rebase_stderr + ); + + if !rebase_output.status.success() { + return Err(JjError::IoError(combined)); + } + + Ok(combined) +} diff --git a/src-tauri/src/jj_lib_ops.rs b/src-tauri/src/jj_lib_ops.rs new file mode 100644 index 00000000..52045bdc --- /dev/null +++ b/src-tauri/src/jj_lib_ops.rs @@ -0,0 +1,29 @@ +// This module is reserved for future jj-lib operations +// Currently all jj operations are handled through the jj CLI in jj.rs + +// TODO (Phase 9 optimization): Implement jj-lib based git status operations +// +// This is an optional optimization that could improve git status performance +// by using jj-lib's workspace operations which leverage libgit2 internally, +// potentially faster than subprocess calls. +// +// Implementation approach: +// 1. Use jj_lib::workspace::Workspace to load the workspace +// 2. Access the repo via workspace.repo() +// 3. Use jj-lib APIs to get working copy changes +// 4. Expose functions like: +// - pub fn jj_get_changed_files(workspace_path: &str) -> Result, String> +// - pub fn jj_get_status(workspace_path: &str) -> Result +// 5. Update git_watcher.rs to use these functions +// +// Note: This requires jj to be initialized for the repo, which is already +// handled by ensure_repo_ready() in lib.rs +// +// Benefits: +// - Potentially faster than git subprocess calls +// - More consistent with jj-based workspace operations +// +// Risks: +// - Adds complexity and potential instability +// - Requires thorough testing to ensure correctness +// - May have edge cases with non-jj repositories diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 88c60716..dedee5dd 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,893 +1,25 @@ +mod commands; mod db; -mod git; -mod git_ops; -mod git2_ops; +mod file_indexer; mod jj; +mod jj_lib_ops; mod local_db; -mod plan_storage; mod pty; -use db::{Database, FileView, GitCacheEntry, Session, Workspace}; -use git::{git_init, is_git_repository, BranchListItem, *}; -use git_ops::{ - BranchCommitInfo, BranchDiffFileChange, BranchDiffFileDiff, DiffHunk, LineSelection, - MergeStrategy, -}; -use ignore::WalkBuilder; -use local_db::{PlanHistoryEntry, PlanHistoryInput}; -use plan_storage::{PlanFile, PlanMetadata}; +use db::Database; use pty::PtyManager; -use std::collections::HashSet; use std::sync::Mutex; use tauri::menu::{MenuBuilder, MenuItemBuilder, SubmenuBuilder}; -use tauri::{AppHandle, Emitter, EventTarget, Manager, State}; +use tauri::{AppHandle, Emitter, EventTarget, Manager}; -struct AppState { +pub(crate) struct AppState { db: Mutex, pty_manager: Mutex, } -// Database commands -#[tauri::command] -fn get_workspaces(repo_path: String) -> Result, String> { - local_db::get_workspaces(&repo_path) -} - -#[tauri::command] -fn add_workspace_to_db( - repo_path: String, - workspace_name: String, - workspace_path: String, - branch_name: String, - metadata: Option, -) -> Result { - local_db::add_workspace(&repo_path, workspace_name, workspace_path, branch_name, metadata) -} - -#[tauri::command] -fn delete_workspace_from_db(repo_path: String, id: i64) -> Result<(), String> { - // Cascade delete sessions (handled by DB foreign key constraint) - local_db::delete_workspace(&repo_path, id) -} - -#[tauri::command] -fn toggle_workspace_pin(repo_path: String, id: i64) -> Result { - local_db::toggle_workspace_pin(&repo_path, id) -} - -#[tauri::command] -fn rebuild_workspaces(repo_path: String) -> Result, String> { - local_db::rebuild_workspaces_from_filesystem(&repo_path) -} - -#[tauri::command] -fn get_git_cache( - state: State, - workspace_path: String, - file_path: Option, - cache_type: String, -) -> Result, String> { - let db = state.db.lock().unwrap(); - db.get_git_cache(&workspace_path, file_path.as_deref(), &cache_type) - .map_err(|e| e.to_string()) -} - -#[tauri::command] -fn set_git_cache( - state: State, - workspace_path: String, - file_path: Option, - cache_type: String, - data: String, -) -> Result<(), String> { - let db = state.db.lock().unwrap(); - db.set_git_cache(&workspace_path, file_path.as_deref(), &cache_type, &data) - .map_err(|e| e.to_string()) -} - -#[tauri::command] -fn invalidate_git_cache(state: State, workspace_path: String) -> Result<(), String> { - let db = state.db.lock().unwrap(); - db.invalidate_git_cache(&workspace_path) - .map_err(|e| e.to_string()) -} - -#[tauri::command] -fn preload_workspace_git_data(state: State, workspace_path: String) -> Result<(), String> { - let changed_files = git_ops::git_get_changed_files(&workspace_path)?; - let serialized_changes = serde_json::to_string(&changed_files).map_err(|e| e.to_string())?; - - { - let db = state.db.lock().unwrap(); - db.set_git_cache(&workspace_path, None, "changed_files", &serialized_changes) - .map_err(|e| e.to_string())?; - } - - let file_paths: HashSet = changed_files - .iter() - .filter_map(|entry| extract_path_from_status_entry(entry)) - .collect(); - - for path in file_paths { - match git_ops::git_get_file_hunks(&workspace_path, &path) { - Ok(hunks) => match serde_json::to_string(&hunks) { - Ok(serialized_hunks) => { - let cache_result = { - let db = state.db.lock().unwrap(); - db.set_git_cache( - &workspace_path, - Some(&path), - "file_hunks", - &serialized_hunks, - ) - }; - if let Err(err) = cache_result { - eprintln!("Failed to cache hunks for {}: {}", path, err); - } - } - Err(err) => { - eprintln!("Failed to serialize hunks for {}: {}", path, err); - } - }, - Err(err) => { - eprintln!("Failed to preload hunks for {}: {}", path, err); - } - } - } - - Ok(()) -} - -#[tauri::command] -fn get_setting(state: State, key: String) -> Result, String> { - let db = state.db.lock().unwrap(); - db.get_setting(&key).map_err(|e| e.to_string()) -} - -#[tauri::command] -fn set_setting(state: State, key: String, value: String) -> Result<(), String> { - let db = state.db.lock().unwrap(); - db.set_setting(&key, &value).map_err(|e| e.to_string()) -} - -#[tauri::command] -fn get_repo_setting( - state: State, - repo_path: String, - key: String, -) -> Result, String> { - let db = state.db.lock().unwrap(); - db.get_repo_setting(&repo_path, &key) - .map_err(|e| e.to_string()) -} - -#[tauri::command] -fn set_repo_setting( - state: State, - repo_path: String, - key: String, - value: String, -) -> Result<(), String> { - let db = state.db.lock().unwrap(); - db.set_repo_setting(&repo_path, &key, &value) - .map_err(|e| e.to_string()) -} - -// JJ Workspace commands -#[tauri::command] -fn jj_create_workspace( - state: State, - app: AppHandle, - repo_path: String, - workspace_name: String, - branch: String, - new_branch: bool, - source_branch: Option, -) -> Result { - // Ensure repo is properly configured - ensure_repo_ready(&state, &app, &repo_path)?; - - // Load inclusion patterns from database - let inclusion_patterns = { - let db = state.db.lock().unwrap(); - db.get_repo_setting(&repo_path, "included_copy_files") - .ok() - .flatten() - .map(|patterns_str| { - patterns_str - .lines() - .map(|s| s.trim().to_string()) - .filter(|s| !s.is_empty()) - .collect::>() - }) - }; - - jj::create_workspace( - &repo_path, - &workspace_name, - &branch, - new_branch, - source_branch.as_deref(), - inclusion_patterns, - ) - .map_err(|e| e.to_string()) -} - -#[tauri::command] -fn jj_list_workspaces( - state: State, - app: AppHandle, - repo_path: String, -) -> Result, String> { - ensure_repo_ready(&state, &app, &repo_path)?; - jj::list_workspaces(&repo_path).map_err(|e| e.to_string()) -} - -#[tauri::command] -fn jj_remove_workspace(repo_path: String, workspace_path: String) -> Result<(), String> { - jj::remove_workspace(&repo_path, &workspace_path).map_err(|e| e.to_string()) -} - -#[tauri::command] -fn jj_get_workspace_info(workspace_path: String) -> Result { - jj::get_workspace_info(&workspace_path).map_err(|e| e.to_string()) -} - -#[tauri::command] -fn git_get_current_branch( - state: State, - app: AppHandle, - repo_path: String, -) -> Result { - ensure_repo_ready(&state, &app, &repo_path)?; - get_current_branch(&repo_path) -} - -#[tauri::command] -fn git_execute_post_create_command( - workspace_path: String, - command: String, -) -> Result { - git::execute_post_create_command(&workspace_path, &command) -} - -#[tauri::command] -fn git_get_status(workspace_path: String) -> Result { - // Try git2 first (faster), fallback to subprocess if it fails - git2_ops::get_status_git2(&workspace_path) - .or_else(|_| get_git_status(&workspace_path)) -} - -#[tauri::command] -fn git_get_branch_info(workspace_path: String) -> Result { - // Try git2 first (faster), fallback to subprocess if it fails - git2_ops::get_branch_info_git2(&workspace_path) - .or_else(|_| get_branch_info(&workspace_path)) -} - -#[tauri::command] -fn git_get_branch_divergence( - workspace_path: String, - base_branch: String, -) -> Result { - // Try git2 first (faster), fallback to subprocess if it fails - git2_ops::get_divergence_git2(&workspace_path, &base_branch) - .or_else(|_| get_branch_divergence(&workspace_path, &base_branch)) -} - -#[tauri::command] -fn git_get_line_diff_stats( - workspace_path: String, - base_branch: String, -) -> Result { - git_ops::git_get_line_diff_stats(&workspace_path, &base_branch) -} - -#[tauri::command] -fn git_get_diff_between_branches( - repo_path: String, - base_branch: String, - head_branch: String, -) -> Result, String> { - git_ops::git_get_diff_between_branches(&repo_path, &base_branch, &head_branch) -} - -#[tauri::command] -fn git_get_changed_files_between_branches( - repo_path: String, - base_branch: String, - head_branch: String, -) -> Result, String> { - git_ops::git_get_changed_files_between_branches(&repo_path, &base_branch, &head_branch) -} - -#[tauri::command] -fn git_get_commits_between_branches( - repo_path: String, - base_branch: String, - head_branch: String, - limit: Option, -) -> Result, String> { - git_ops::git_get_commits_between_branches(&repo_path, &base_branch, &head_branch, limit) -} - -#[tauri::command] -fn git_list_branches(repo_path: String) -> Result, String> { - list_branches(&repo_path) -} - -#[tauri::command] -fn git_list_branches_detailed(repo_path: String) -> Result, String> { - list_branches_detailed(&repo_path) -} - -#[tauri::command] -fn git_checkout_branch( - repo_path: String, - branch_name: String, - create_new: bool, -) -> Result { - checkout_branch(&repo_path, &branch_name, create_new) -} - -#[tauri::command] -fn git_is_repository(path: String) -> Result { - is_git_repository(&path) -} - -#[tauri::command] -fn git_init_repo(path: String) -> Result { - git_init(&path) -} - -#[tauri::command] -fn git_list_gitignored_files(repo_path: String) -> Result, String> { - list_gitignored_files(&repo_path) -} - -#[tauri::command] -fn git_merge( - repo_path: String, - branch: String, - strategy: String, - commit_message: Option, -) -> Result { - let strategy = match strategy.as_str() { - "regular" => MergeStrategy::Regular, - "squash" => MergeStrategy::Squash, - "no_ff" => MergeStrategy::NoFastForward, - "ff_only" => MergeStrategy::FastForwardOnly, - other => { - return Err(format!("Unsupported merge strategy: {}", other)); - } - }; - - git_ops::git_merge(&repo_path, &branch, strategy, commit_message.as_deref()) -} - -#[tauri::command] -fn git_discard_all_changes(workspace_path: String) -> Result { - git_ops::git_discard_all_changes(&workspace_path) -} - -#[tauri::command] -fn git_discard_files(workspace_path: String, file_paths: Vec) -> Result { - git_ops::git_discard_files(&workspace_path, file_paths) -} - -#[tauri::command] -fn git_has_uncommitted_changes(workspace_path: String) -> Result { - git_ops::has_uncommitted_changes(&workspace_path) -} - -#[tauri::command] -fn git_stash_push_files( - workspace_path: String, - file_paths: Vec, - message: String, -) -> Result { - git::git_stash_push_files(&workspace_path, file_paths, &message) -} - -#[tauri::command] -fn git_stash_pop(workspace_path: String) -> Result { - git::git_stash_pop(&workspace_path) -} - -// PTY commands -#[tauri::command] -fn pty_create_session( - state: State, - app: AppHandle, - session_id: String, - working_dir: Option, - shell: Option, - initial_command: Option, -) -> Result<(), String> { - let pty_manager = state.pty_manager.lock().unwrap(); - let sid = session_id.clone(); - - pty_manager.create_session( - session_id, - working_dir, - shell, - initial_command, - Box::new(move |data| { - let _ = app.emit(&format!("pty-data-{}", sid), data); - }), - ) -} - -#[tauri::command] -fn pty_session_exists(state: State, session_id: String) -> Result { - let pty_manager = state.pty_manager.lock().unwrap(); - Ok(pty_manager.session_exists(&session_id)) -} - -#[tauri::command] -fn pty_write(state: State, session_id: String, data: String) -> Result<(), String> { - let pty_manager = state.pty_manager.lock().unwrap(); - pty_manager.write_to_session(&session_id, &data) -} - -#[tauri::command] -fn pty_resize( - state: State, - session_id: String, - rows: u16, - cols: u16, -) -> Result<(), String> { - let pty_manager = state.pty_manager.lock().unwrap(); - pty_manager.resize_session(&session_id, rows, cols) -} - -#[tauri::command] -fn pty_close(state: State, session_id: String) -> Result<(), String> { - let pty_manager = state.pty_manager.lock().unwrap(); - pty_manager.close_session(&session_id) -} - -// File system commands -#[tauri::command] -fn read_file(path: String) -> Result { - std::fs::read_to_string(path).map_err(|e| e.to_string()) -} - -#[derive(serde::Serialize)] -struct DirectoryEntry { - name: String, - path: String, - is_directory: bool, -} - -#[tauri::command] -fn list_directory(path: String) -> Result, String> { - use std::path::Path; - - let base_path = Path::new(&path); - let mut files = Vec::new(); - - // Use ignore::WalkBuilder to respect .gitignore patterns - let walker = WalkBuilder::new(&path) - .max_depth(Some(1)) // Only immediate children - .hidden(false) // Show hidden files (except those in .gitignore) - .git_ignore(true) // Respect .gitignore patterns - .git_global(true) // Respect global gitignore - .git_exclude(true) // Respect .git/info/exclude - .parents(true) // Check parent directories for ignore files - .build(); - - for entry in walker { - if let Ok(entry) = entry { - let entry_path = entry.path(); - - // Skip the base directory itself - if entry_path == base_path { - continue; - } - - if let Some(name) = entry_path.file_name().and_then(|n| n.to_str()) { - let is_dir = entry_path.is_dir(); - files.push(DirectoryEntry { - name: name.to_string(), - path: entry_path.to_string_lossy().to_string(), - is_directory: is_dir, - }); - } - } - } - - // Sort: directories first, then files - files.sort_by(|a, b| match (a.is_directory, b.is_directory) { - (true, false) => std::cmp::Ordering::Less, - (false, true) => std::cmp::Ordering::Greater, - _ => a.name.cmp(&b.name), - }); - - Ok(files) -} - -// Git operations -#[tauri::command] -fn git_commit(workspace_path: String, message: String) -> Result { - git_ops::git_commit(&workspace_path, &message) -} - -#[tauri::command] -fn git_add_all(workspace_path: String) -> Result { - git_ops::git_add_all(&workspace_path) -} - -#[tauri::command] -fn git_unstage_all(workspace_path: String) -> Result { - git_ops::git_unstage_all(&workspace_path) -} - -#[tauri::command] -fn git_push(workspace_path: String) -> Result { - git_ops::git_push(&workspace_path) -} - -#[tauri::command] -fn git_push_force(workspace_path: String) -> Result { - git_ops::git_push_force(&workspace_path) -} - -#[tauri::command] -fn git_commit_amend(workspace_path: String, message: String) -> Result { - git_ops::git_commit_amend(&workspace_path, &message) -} - -#[tauri::command] -fn git_pull(workspace_path: String) -> Result { - git_ops::git_pull(&workspace_path) -} - -#[tauri::command] -fn git_fetch(workspace_path: String) -> Result { - git_ops::git_fetch(&workspace_path) -} - -#[tauri::command] -fn git_stage_file(workspace_path: String, file_path: String) -> Result { - git_ops::git_stage_file(&workspace_path, &file_path) -} - -#[tauri::command] -fn git_unstage_file(workspace_path: String, file_path: String) -> Result { - git_ops::git_unstage_file(&workspace_path, &file_path) -} - -#[tauri::command] -fn git_get_changed_files(workspace_path: String) -> Result, String> { - git_ops::git_get_changed_files(&workspace_path) -} - -fn extract_path_from_status_entry(entry: &str) -> Option { - if entry.starts_with("?? ") { - return Some(entry[3..].trim().to_string()); - } - - if entry.len() < 4 { - return None; - } - - let raw = entry[3..].trim(); - if raw.is_empty() { - return None; - } - - if let Some(idx) = raw.rfind(" -> ") { - Some(raw[idx + 4..].trim().to_string()) - } else { - Some(raw.to_string()) - } -} - -#[tauri::command] -fn git_stage_hunk(workspace_path: String, patch: String) -> Result { - git_ops::git_stage_hunk(&workspace_path, &patch) -} - -#[tauri::command] -fn git_unstage_hunk(workspace_path: String, patch: String) -> Result { - git_ops::git_unstage_hunk(&workspace_path, &patch) -} - -#[tauri::command] -fn git_get_file_hunks(workspace_path: String, file_path: String) -> Result, String> { - git_ops::git_get_file_hunks(&workspace_path, &file_path) -} - -#[tauri::command] -fn git_get_file_lines( - workspace_path: String, - file_path: String, - is_staged: bool, - start_line: usize, - end_line: usize, -) -> Result { - git_ops::git_get_file_lines(&workspace_path, &file_path, is_staged, start_line, end_line) -} - -#[tauri::command] -fn git_stage_selected_lines( - workspace_path: String, - file_path: String, - selections: Vec, - metadata_lines: Vec, - hunks: Vec<(String, Vec)>, -) -> Result { - git_ops::git_stage_selected_lines( - &workspace_path, - &file_path, - selections, - metadata_lines, - hunks, - ) -} - -#[tauri::command] -fn git_unstage_selected_lines( - workspace_path: String, - file_path: String, - selections: Vec, - metadata_lines: Vec, - hunks: Vec<(String, Vec)>, -) -> Result { - git_ops::git_unstage_selected_lines( - &workspace_path, - &file_path, - selections, - metadata_lines, - hunks, - ) -} - -// Plan history commands -#[tauri::command] -fn save_executed_plan_command( - repo_path: String, - workspace_id: i64, - plan_data: PlanHistoryInput, -) -> Result { - local_db::save_executed_plan(&repo_path, workspace_id, plan_data) -} - -#[tauri::command] -fn get_workspace_plans_command( - repo_path: String, - workspace_id: i64, - limit: Option, -) -> Result, String> { - local_db::get_workspace_plans(&repo_path, workspace_id, limit) -} - -#[tauri::command] -fn get_all_workspace_plans_command( - repo_path: String, - workspace_id: i64, -) -> Result, String> { - local_db::get_all_workspace_plans(&repo_path, workspace_id) -} - -// Plan storage commands -#[tauri::command] -fn save_plan_to_file( - repo_path: String, - plan_id: String, - content: String, - metadata: PlanMetadata, -) -> Result<(), String> { - plan_storage::save_plan_to_file(&repo_path, &plan_id, &content, metadata) -} - -#[tauri::command] -fn load_plans_from_files(repo_path: String) -> Result, String> { - plan_storage::load_plans_from_files(&repo_path) -} - -#[tauri::command] -fn get_plan_file(repo_path: String, plan_id: String) -> Result { - plan_storage::get_plan_file(&repo_path, &plan_id) -} - -#[tauri::command] -fn delete_plan_file(repo_path: String, plan_id: String) -> Result<(), String> { - plan_storage::delete_plan_file(&repo_path, &plan_id) -} - -// Session management commands -#[tauri::command] -fn create_session( - repo_path: String, - workspace_id: Option, - name: String, - plan_title: Option, -) -> Result { - local_db::add_session(&repo_path, workspace_id, name, plan_title) -} - -#[tauri::command] -fn get_sessions(repo_path: String) -> Result, String> { - local_db::get_sessions(&repo_path) -} - -#[tauri::command] -fn update_session_access(repo_path: String, id: i64) -> Result<(), String> { - local_db::update_session_access(&repo_path, id) -} - -#[tauri::command] -fn update_session_name(repo_path: String, id: i64, name: String) -> Result<(), String> { - local_db::update_session_name(&repo_path, id, name) -} - -#[tauri::command] -fn delete_session(repo_path: String, id: i64) -> Result<(), String> { - local_db::delete_session(&repo_path, id) -} - -#[tauri::command] -fn get_session_model(repo_path: String, id: i64) -> Result, String> { - local_db::get_session_model(&repo_path, id) -} - -#[tauri::command] -fn set_session_model(repo_path: String, id: i64, model: Option) -> Result<(), String> { - local_db::set_session_model(&repo_path, id, model) -} - -// File view tracking commands -#[tauri::command] -fn mark_file_viewed( - state: State, - workspace_path: String, - file_path: String, - content_hash: String, -) -> Result<(), String> { - let db = state.db.lock().unwrap(); - db.mark_file_viewed(&workspace_path, &file_path, &content_hash) - .map_err(|e| e.to_string()) -} - -#[tauri::command] -fn unmark_file_viewed( - state: State, - workspace_path: String, - file_path: String, -) -> Result<(), String> { - let db = state.db.lock().unwrap(); - db.unmark_file_viewed(&workspace_path, &file_path) - .map_err(|e| e.to_string()) -} - -#[tauri::command] -fn get_viewed_files( - state: State, - workspace_path: String, -) -> Result, String> { - let db = state.db.lock().unwrap(); - db.get_viewed_files(&workspace_path) - .map_err(|e| e.to_string()) -} - -#[tauri::command] -fn clear_all_viewed_files(state: State, workspace_path: String) -> Result<(), String> { - let db = state.db.lock().unwrap(); - db.clear_all_viewed_files(&workspace_path) - .map_err(|e| e.to_string()) -} - -/// Check if a path has a jj workspace -#[tauri::command] -fn jj_is_workspace(repo_path: String) -> bool { - jj::is_jj_workspace(&repo_path) -} - -/// Manually initialize jj for a repository -#[tauri::command] -fn jj_init(state: State, repo_path: String) -> Result { - let db = state.db.lock().unwrap(); - jj::ensure_jj_initialized(&db, &repo_path).map_err(|e| e.to_string()) -} - -/// Ensure repository is properly configured before operations -/// This includes git config and jj initialization -/// Emits event to frontend if initialization fails -fn ensure_repo_ready( - state: &State, - app: &AppHandle, - repo_path: &str, -) -> Result<(), String> { - // Only initialize if it's a git repository - if !is_git_repository(repo_path).unwrap_or(false) { - return Ok(()); - } - - #[derive(Clone, serde::Serialize)] - struct InitError { - repo_path: String, - error: String, - error_type: String, - } - - // Ensure .jj and .treq are in .gitignore (runs on every repo open) - if let Err(ref error) = jj::ensure_gitignore_entries(repo_path) { - let _ = app.emit( - "repo-init-error", - InitError { - repo_path: repo_path.to_string(), - error: error.to_string(), - error_type: "gitignore".to_string(), - }, - ); - } - - // Get DB and check/initialize git config - let git_result = { - let db = state.db.lock().unwrap(); - git::ensure_repo_configured(&db, repo_path) - }; - - // If git config failed, emit event for frontend notification - if let Err(ref error) = git_result { - let _ = app.emit( - "repo-init-error", - InitError { - repo_path: repo_path.to_string(), - error: error.clone(), - error_type: "git-config".to_string(), - }, - ); - } - - // Initialize jj for git repository - let jj_result = { - let db = state.db.lock().unwrap(); - jj::ensure_jj_initialized(&db, repo_path) - }; - - match jj_result { - Ok(true) => { - // jj was newly initialized - emit success event - #[derive(Clone, serde::Serialize)] - struct JjInitSuccess { - repo_path: String, - } - let _ = app.emit( - "jj-initialized", - JjInitSuccess { - repo_path: repo_path.to_string(), - }, - ); - } - Ok(false) => { - // Already initialized, no action needed - } - Err(jj::JjError::AlreadyInitialized) | Err(jj::JjError::NotGitRepository) => { - // Not an error, just skip - } - Err(ref error) => { - // Other errors should be reported - let _ = app.emit( - "repo-init-error", - InitError { - repo_path: repo_path.to_string(), - error: error.to_string(), - error_type: "jj-init".to_string(), - }, - ); - } - } - - // Don't block operation even if init failed - Ok(()) -} - /// Emits an event only to the focused webview window. /// Falls back to broadcasting if no focused window is found. -fn emit_to_focused(app: &AppHandle, event: &str, payload: S) { +pub fn emit_to_focused(app: &AppHandle, event: &str, payload: S) { for (label, window) in app.webview_windows() { if window.is_focused().unwrap_or(false) { let _ = app.emit_to(EventTarget::webview_window(&label), event, payload); @@ -1072,90 +204,56 @@ pub fn run() { Ok(()) }) .invoke_handler(tauri::generate_handler![ - get_workspaces, - add_workspace_to_db, - delete_workspace_from_db, - toggle_workspace_pin, - rebuild_workspaces, - get_setting, - set_setting, - get_repo_setting, - set_repo_setting, - get_git_cache, - set_git_cache, - invalidate_git_cache, - preload_workspace_git_data, - jj_create_workspace, - jj_list_workspaces, - jj_remove_workspace, - jj_get_workspace_info, - jj_is_workspace, - jj_init, - git_get_current_branch, - git_execute_post_create_command, - git_get_status, - git_get_branch_info, - git_get_branch_divergence, - git_get_line_diff_stats, - git_get_diff_between_branches, - git_get_changed_files_between_branches, - git_get_commits_between_branches, - git_list_branches, - git_list_branches_detailed, - git_checkout_branch, - git_is_repository, - git_init_repo, - git_list_gitignored_files, - git_merge, - git_discard_all_changes, - git_discard_files, - git_has_uncommitted_changes, - git_stash_push_files, - git_stash_pop, - git_commit, - git_commit_amend, - git_add_all, - git_unstage_all, - git_push, - git_push_force, - git_pull, - git_fetch, - git_stage_file, - git_unstage_file, - git_stage_hunk, - git_unstage_hunk, - git_get_changed_files, - git_get_file_hunks, - git_get_file_lines, - git_stage_selected_lines, - git_unstage_selected_lines, - pty_create_session, - pty_session_exists, - pty_write, - pty_resize, - pty_close, - read_file, - list_directory, - save_executed_plan_command, - get_workspace_plans_command, - get_all_workspace_plans_command, - save_plan_to_file, - load_plans_from_files, - get_plan_file, - delete_plan_file, - create_session, - get_sessions, - update_session_access, - update_session_name, - delete_session, - get_session_model, - set_session_model, - mark_file_viewed, - unmark_file_viewed, - get_viewed_files, - clear_all_viewed_files, - jj_is_workspace, - jj_init, + commands::get_workspaces, + commands::add_workspace_to_db, + commands::delete_workspace_from_db, + commands::rebuild_workspaces, + commands::update_workspace_metadata, + commands::set_workspace_target_branch, + commands::ensure_workspace_indexed, + commands::get_setting, + commands::get_settings_batch, + commands::set_setting, + commands::get_repo_setting, + commands::set_repo_setting, + commands::jj_create_workspace, + commands::jj_list_workspaces, + commands::jj_remove_workspace, + commands::jj_get_workspace_info, + commands::jj_squash_to_workspace, + commands::jj_get_changed_files, + commands::jj_get_file_hunks, + commands::jj_get_file_lines, + commands::jj_restore_file, + commands::jj_restore_all, + commands::jj_commit, + commands::jj_is_workspace, + commands::jj_init, + commands::jj_rebase_onto, + commands::jj_get_conflicted_files, + commands::jj_get_default_branch, + commands::jj_push, + commands::jj_pull, + commands::pty_create_session, + commands::pty_session_exists, + commands::pty_write, + commands::pty_resize, + commands::pty_close, + commands::read_file, + commands::list_directory, + commands::list_directory_cached, + commands::get_change_indicators, + commands::create_session, + commands::get_sessions, + commands::update_session_access, + commands::update_session_name, + commands::delete_session, + commands::get_session_model, + commands::set_session_model, + commands::mark_file_viewed, + commands::unmark_file_viewed, + commands::get_viewed_files, + commands::clear_all_viewed_files, ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src-tauri/src/local_db.rs b/src-tauri/src/local_db.rs index 53e05dcf..97ebd2e1 100644 --- a/src-tauri/src/local_db.rs +++ b/src-tauri/src/local_db.rs @@ -1,35 +1,46 @@ use chrono::Utc; use rusqlite::{params, Connection}; use serde::{Deserialize, Serialize}; -use serde_json::Value; +use std::collections::HashSet; use std::fs; use std::path::{Path, PathBuf}; +use std::sync::{Mutex, OnceLock}; // Re-export types from db module use crate::db::{Session, Workspace}; -#[derive(Debug, Serialize, Deserialize)] -pub struct PlanHistoryEntry { +// ============================================================================ +// Database Initialization Tracker +// ============================================================================ + +/// Track which local databases have been initialized to avoid repeated schema checks +static INITIALIZED_DBS: OnceLock>> = OnceLock::new(); + +// ============================================================================ +// Git Cache Types +// ============================================================================ + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct CachedFileChange { pub id: i64, - pub workspace_id: i64, - pub title: String, - #[serde(rename = "type")] - pub plan_type: String, - pub content: Value, - pub created_at: String, - pub executed_at: String, - pub status: String, + pub workspace_id: Option, + pub file_path: String, + pub workspace_status: Option, + pub is_untracked: bool, + pub hunks_json: Option, + pub updated_at: String, } -#[derive(Debug, Deserialize)] -pub struct PlanHistoryInput { - pub title: String, - #[serde(rename = "type")] - pub plan_type: String, - pub content: Value, - pub created_at: Option, - pub executed_at: Option, - pub status: Option, +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct CachedWorkspaceFile { + pub id: i64, + pub workspace_id: Option, + pub file_path: String, + pub relative_path: String, + pub is_directory: bool, + pub parent_path: Option, + pub cached_at: String, + pub mtime: Option, // File modification time (unix timestamp) } pub fn get_local_db_path(repo_path: &str) -> PathBuf { @@ -45,72 +56,6 @@ pub fn init_local_db(repo_path: &str) -> Result<(), String> { let conn = Connection::open(db_path).map_err(|e| format!("Failed to open local db: {}", e))?; - conn.execute( - "CREATE TABLE IF NOT EXISTS plans ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - workspace_id INTEGER NOT NULL, - title TEXT NOT NULL, - type TEXT NOT NULL, - content TEXT NOT NULL, - created_at TEXT NOT NULL, - executed_at TEXT NOT NULL, - status TEXT NOT NULL - )", - [], - ) - .map_err(|e| format!("Failed to create plans table: {}", e))?; - - // Migration: Rename worktree_id to workspace_id in plans table - let has_worktree_col: Result = conn.query_row( - "SELECT COUNT(*) FROM pragma_table_info('plans') WHERE name='worktree_id'", - [], - |row| row.get(0), - ); - - if let Ok(count) = has_worktree_col { - if count > 0 { - // SQLite doesn't support RENAME COLUMN in older versions, so recreate the table - conn.execute( - "CREATE TABLE plans_new ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - workspace_id INTEGER NOT NULL, - title TEXT NOT NULL, - type TEXT NOT NULL, - content TEXT NOT NULL, - created_at TEXT NOT NULL, - executed_at TEXT NOT NULL, - status TEXT NOT NULL - )", - [], - ) - .map_err(|e| format!("Failed to create plans_new table: {}", e))?; - - conn.execute( - "INSERT INTO plans_new SELECT id, worktree_id, title, type, content, created_at, executed_at, status FROM plans", - [], - ) - .map_err(|e| format!("Failed to migrate plans data: {}", e))?; - - conn.execute("DROP TABLE plans", []) - .map_err(|e| format!("Failed to drop old plans table: {}", e))?; - - conn.execute("ALTER TABLE plans_new RENAME TO plans", []) - .map_err(|e| format!("Failed to rename plans_new to plans: {}", e))?; - } - } - - conn.execute( - "CREATE INDEX IF NOT EXISTS idx_plans_workspace_id ON plans(workspace_id)", - [], - ) - .map_err(|e| format!("Failed to create workspace index: {}", e))?; - - conn.execute( - "CREATE INDEX IF NOT EXISTS idx_plans_executed_at ON plans(executed_at)", - [], - ) - .map_err(|e| format!("Failed to create executed_at index: {}", e))?; - // Create workspaces table conn.execute( "CREATE TABLE IF NOT EXISTS workspaces ( @@ -120,7 +65,7 @@ pub fn init_local_db(repo_path: &str) -> Result<(), String> { branch_name TEXT NOT NULL, created_at TEXT NOT NULL, metadata TEXT, - is_pinned INTEGER DEFAULT 0 + target_branch TEXT )", [], ) @@ -132,6 +77,12 @@ pub fn init_local_db(repo_path: &str) -> Result<(), String> { ) .map_err(|e| format!("Failed to create workspaces branch index: {}", e))?; + // Migration: Add target_branch column if it doesn't exist + let _ = conn.execute( + "ALTER TABLE workspaces ADD COLUMN target_branch TEXT", + [], + ); + // Create sessions table conn.execute( "CREATE TABLE IF NOT EXISTS sessions ( @@ -140,7 +91,6 @@ pub fn init_local_db(repo_path: &str) -> Result<(), String> { name TEXT NOT NULL, created_at TEXT NOT NULL, last_accessed TEXT NOT NULL, - plan_title TEXT, model TEXT, FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE )", @@ -165,7 +115,6 @@ pub fn init_local_db(repo_path: &str) -> Result<(), String> { name TEXT NOT NULL, created_at TEXT NOT NULL, last_accessed TEXT NOT NULL, - plan_title TEXT, model TEXT, FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE )", @@ -174,7 +123,7 @@ pub fn init_local_db(repo_path: &str) -> Result<(), String> { .map_err(|e| format!("Failed to create sessions_new table: {}", e))?; conn.execute( - "INSERT INTO sessions_new SELECT id, worktree_id, name, created_at, last_accessed, plan_title, model FROM sessions", + "INSERT INTO sessions_new SELECT id, worktree_id, name, created_at, last_accessed, model FROM sessions", [], ) .map_err(|e| format!("Failed to migrate sessions data: {}", e))?; @@ -199,105 +148,90 @@ pub fn init_local_db(repo_path: &str) -> Result<(), String> { ) .map_err(|e| format!("Failed to create sessions workspace index: {}", e))?; - Ok(()) -} + // Migration: Drop old tables if they exist + let _ = conn.execute("DROP TABLE IF EXISTS git_file_hunks", []); + let _ = conn.execute("DROP TABLE IF EXISTS git_changed_files", []); + let _ = conn.execute("DROP INDEX IF EXISTS idx_git_file_hunks_workspace", []); + let _ = conn.execute("DROP INDEX IF EXISTS idx_git_changed_files_workspace", []); -fn get_connection(repo_path: &str) -> Result { - init_local_db(repo_path)?; - let db_path = get_local_db_path(repo_path); - Connection::open(db_path).map_err(|e| format!("Failed to open local db: {}", e)) -} - -pub fn save_executed_plan( - repo_path: &str, - workspace_id: i64, - plan_data: PlanHistoryInput, -) -> Result { - let conn = get_connection(repo_path)?; - let created_at = plan_data - .created_at - .unwrap_or_else(|| Utc::now().to_rfc3339()); - let executed_at = plan_data - .executed_at - .unwrap_or_else(|| Utc::now().to_rfc3339()); - let status = plan_data.status.unwrap_or_else(|| "executed".to_string()); - let content = serde_json::to_string(&plan_data.content) - .map_err(|e| format!("Failed to serialize plan content: {}", e))?; + // Create consolidated changes cache table + conn.execute( + "CREATE TABLE IF NOT EXISTS changed_files ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + workspace_id INTEGER, + file_path TEXT NOT NULL, + workspace_status TEXT, + is_untracked INTEGER NOT NULL DEFAULT 0, + hunks_json TEXT, + updated_at TEXT NOT NULL, + FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE, + UNIQUE(workspace_id, file_path) + )", + [], + ) + .map_err(|e| format!("Failed to create changed_files table: {}", e))?; conn.execute( - "INSERT INTO plans (workspace_id, title, type, content, created_at, executed_at, status) - VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)", - params![ - workspace_id, - plan_data.title, - plan_data.plan_type, - content, - created_at, - executed_at, - status, - ], + "CREATE INDEX IF NOT EXISTS idx_changed_files_workspace ON changed_files(workspace_id)", + [], ) - .map_err(|e| format!("Failed to insert plan history: {}", e))?; + .map_err(|e| format!("Failed to create changed_files workspace index: {}", e))?; - Ok(conn.last_insert_rowid()) -} + // Create workspace files cache table + conn.execute( + "CREATE TABLE IF NOT EXISTS workspace_files ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + workspace_id INTEGER, + file_path TEXT NOT NULL, + relative_path TEXT NOT NULL, + is_directory INTEGER NOT NULL DEFAULT 0, + parent_path TEXT, + cached_at TEXT NOT NULL, + mtime INTEGER, + FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE, + UNIQUE(workspace_id, file_path) + )", + [], + ) + .map_err(|e| format!("Failed to create workspace_files table: {}", e))?; -pub fn get_workspace_plans( - repo_path: &str, - workspace_id: i64, - limit: Option, -) -> Result, String> { - let conn = get_connection(repo_path)?; - let mut query = String::from( - "SELECT id, workspace_id, title, type, content, created_at, executed_at, status - FROM plans WHERE workspace_id = ?1 - ORDER BY datetime(executed_at) DESC, id DESC", + // Migration: Add mtime column if it doesn't exist + let _ = conn.execute( + "ALTER TABLE workspace_files ADD COLUMN mtime INTEGER", + [], ); - if let Some(limit) = limit { - query.push_str(" LIMIT ?2"); - let mut stmt = conn - .prepare(&query) - .map_err(|e| format!("Failed to prepare plan query: {}", e))?; - let rows = stmt - .query_map(params![workspace_id, limit], |row| row_to_plan(row)) - .map_err(|e| format!("Failed to query plans: {}", e))?; - return rows - .collect::, _>>() - .map_err(|e| e.to_string()); - } + conn.execute( + "CREATE INDEX IF NOT EXISTS idx_workspace_files_workspace ON workspace_files(workspace_id)", + [], + ) + .map_err(|e| format!("Failed to create workspace_files workspace index: {}", e))?; - let mut stmt = conn - .prepare(&query) - .map_err(|e| format!("Failed to prepare plan query: {}", e))?; - let rows = stmt - .query_map(params![workspace_id], |row| row_to_plan(row)) - .map_err(|e| format!("Failed to query plans: {}", e))?; - rows.collect::, _>>() - .map_err(|e| e.to_string()) -} + conn.execute( + "CREATE INDEX IF NOT EXISTS idx_workspace_files_parent ON workspace_files(workspace_id, parent_path)", + [], + ) + .map_err(|e| format!("Failed to create workspace_files parent index: {}", e))?; -pub fn get_all_workspace_plans( - repo_path: &str, - workspace_id: i64, -) -> Result, String> { - get_workspace_plans(repo_path, workspace_id, None) + Ok(()) } -fn row_to_plan(row: &rusqlite::Row) -> rusqlite::Result { - let content: String = row.get(4)?; - let content_value = serde_json::from_str(&content).unwrap_or(Value::Null); - - Ok(PlanHistoryEntry { - id: row.get(0)?, - workspace_id: row.get(1)?, - title: row.get(2)?, - plan_type: row.get(3)?, - content: content_value, - created_at: row.get(5)?, - executed_at: row.get(6)?, - status: row.get(7)?, - }) +fn get_connection(repo_path: &str) -> Result { + // Check if this database has already been initialized + let initialized = INITIALIZED_DBS.get_or_init(|| Mutex::new(HashSet::new())); + let db_key = repo_path.to_string(); + + { + let guard = initialized.lock().unwrap(); + if !guard.contains(&db_key) { + drop(guard); // Release lock before calling init + init_local_db(repo_path)?; + initialized.lock().unwrap().insert(db_key); + } + } + + let db_path = get_local_db_path(repo_path); + Connection::open(db_path).map_err(|e| format!("Failed to open local db: {}", e)) } // ============================================================================ @@ -307,7 +241,7 @@ fn row_to_plan(row: &rusqlite::Row) -> rusqlite::Result { pub fn get_workspaces(repo_path: &str) -> Result, String> { let conn = get_connection(repo_path)?; let mut stmt = conn - .prepare("SELECT id, workspace_name, workspace_path, branch_name, created_at, metadata, is_pinned FROM workspaces ORDER BY is_pinned DESC, branch_name COLLATE NOCASE ASC") + .prepare("SELECT id, workspace_name, workspace_path, branch_name, created_at, metadata, target_branch FROM workspaces ORDER BY branch_name COLLATE NOCASE ASC") .map_err(|e| format!("Failed to prepare workspaces query: {}", e))?; let workspaces = stmt @@ -320,7 +254,7 @@ pub fn get_workspaces(repo_path: &str) -> Result, String> { branch_name: row.get(3)?, created_at: row.get(4)?, metadata: row.get(5)?, - is_pinned: row.get::<_, i64>(6)? != 0, + target_branch: row.get(6)?, }) }) .map_err(|e| format!("Failed to query workspaces: {}", e))?; @@ -341,9 +275,9 @@ pub fn add_workspace( let created_at = Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO workspaces (workspace_name, workspace_path, branch_name, created_at, metadata, is_pinned) - VALUES (?1, ?2, ?3, ?4, ?5, ?6)", - params![workspace_name, workspace_path, branch_name, created_at, metadata, 0], + "INSERT INTO workspaces (workspace_name, workspace_path, branch_name, created_at, metadata) + VALUES (?1, ?2, ?3, ?4, ?5)", + params![workspace_name, workspace_path, branch_name, created_at, metadata], ) .map_err(|e| format!("Failed to insert workspace: {}", e))?; @@ -357,28 +291,32 @@ pub fn delete_workspace(repo_path: &str, id: i64) -> Result<(), String> { Ok(()) } -pub fn toggle_workspace_pin(repo_path: &str, id: i64) -> Result { +pub fn update_workspace_metadata( + repo_path: &str, + id: i64, + metadata: &str, +) -> Result<(), String> { let conn = get_connection(repo_path)?; - - // Get current pin status - let mut stmt = conn - .prepare("SELECT is_pinned FROM workspaces WHERE id = ?1") - .map_err(|e| format!("Failed to prepare query: {}", e))?; - - let current_pinned: i64 = stmt - .query_row([id], |row| row.get(0)) - .map_err(|e| format!("Failed to get pin status: {}", e))?; - - // Toggle it - let new_pinned = if current_pinned != 0 { 0 } else { 1 }; - conn.execute( - "UPDATE workspaces SET is_pinned = ?1 WHERE id = ?2", - params![new_pinned, id], + "UPDATE workspaces SET metadata = ?1 WHERE id = ?2", + params![metadata, id], ) - .map_err(|e| format!("Failed to update pin status: {}", e))?; + .map_err(|e| format!("Failed to update workspace metadata: {}", e))?; + Ok(()) +} - Ok(new_pinned != 0) +pub fn update_workspace_target_branch( + repo_path: &str, + id: i64, + target_branch: &str, +) -> Result<(), String> { + let conn = get_connection(repo_path)?; + conn.execute( + "UPDATE workspaces SET target_branch = ?1 WHERE id = ?2", + params![target_branch, id], + ) + .map_err(|e| format!("Failed to update workspace target branch: {}", e))?; + Ok(()) } pub fn rebuild_workspaces_from_filesystem(repo_path: &str) -> Result, String> { @@ -441,7 +379,7 @@ pub fn rebuild_workspaces_from_filesystem(repo_path: &str) -> Result Result Result { use std::process::Command; @@ -459,7 +398,41 @@ fn get_workspace_branch(workspace_path: &str) -> Result { .map_err(|e| e.to_string())?; if output.status.success() { - Ok(String::from_utf8_lossy(&output.stdout).trim().to_string()) + let branch = String::from_utf8_lossy(&output.stdout).trim().to_string(); + + // If not detached, return the branch name + if branch != "HEAD" { + return Ok(branch); + } + + // Git is in detached HEAD - try to get branch from jj bookmark + // jj bookmark list outputs: bookmark_name: + if let Ok(jj_output) = Command::new("jj") + .current_dir(workspace_path) + .args(["bookmark", "list", "--no-pager"]) + .output() + { + if jj_output.status.success() { + let bookmarks = String::from_utf8_lossy(&jj_output.stdout); + // Find the first non-remote bookmark (local bookmarks don't have @) + for line in bookmarks.lines() { + let line = line.trim(); + if line.is_empty() || line.contains('@') { + continue; + } + // Extract bookmark name (before the colon) + if let Some(name) = line.split(':').next() { + let name = name.trim(); + if !name.is_empty() { + return Ok(name.to_string()); + } + } + } + } + } + + // Still detached with no bookmark - return HEAD + Ok(branch) } else { Err(String::from_utf8_lossy(&output.stderr).to_string()) } @@ -472,7 +445,7 @@ fn get_workspace_branch(workspace_path: &str) -> Result { pub fn get_sessions(repo_path: &str) -> Result, String> { let conn = get_connection(repo_path)?; let mut stmt = conn - .prepare("SELECT id, workspace_id, name, created_at, last_accessed, plan_title, model FROM sessions ORDER BY created_at ASC") + .prepare("SELECT id, workspace_id, name, created_at, last_accessed, model FROM sessions ORDER BY created_at ASC") .map_err(|e| format!("Failed to prepare sessions query: {}", e))?; let sessions = stmt @@ -483,8 +456,7 @@ pub fn get_sessions(repo_path: &str) -> Result, String> { name: row.get(2)?, created_at: row.get(3)?, last_accessed: row.get(4)?, - plan_title: row.get(5)?, - model: row.get(6)?, + model: row.get(5)?, }) }) .map_err(|e| format!("Failed to query sessions: {}", e))?; @@ -498,15 +470,14 @@ pub fn add_session( repo_path: &str, workspace_id: Option, name: String, - plan_title: Option, ) -> Result { let conn = get_connection(repo_path)?; let now = Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO sessions (workspace_id, name, created_at, last_accessed, plan_title, model) - VALUES (?1, ?2, ?3, ?4, ?5, ?6)", - params![workspace_id, name, now, now, plan_title, None::], + "INSERT INTO sessions (workspace_id, name, created_at, last_accessed, model) + VALUES (?1, ?2, ?3, ?4, ?5)", + params![workspace_id, name, now, now, None::], ) .map_err(|e| format!("Failed to insert session: {}", e))?; @@ -567,3 +538,242 @@ pub fn set_session_model(repo_path: &str, id: i64, model: Option) -> Res Ok(()) } + +// ============================================================================ +// Git Cache Functions +// ============================================================================ + +/// Get all cached changed files for a workspace +pub fn get_cached_changes( + repo_path: &str, + workspace_id: Option, +) -> Result, String> { + let conn = get_connection(repo_path)?; + let mut stmt = conn + .prepare( + "SELECT id, workspace_id, file_path, staged_status, workspace_status, is_untracked, hunks_json, updated_at + FROM changed_files + WHERE workspace_id IS ?1 + ORDER BY file_path", + ) + .map_err(|e| format!("Failed to prepare query: {}", e))?; + + let changes = stmt + .query_map([workspace_id], |row| { + Ok(CachedFileChange { + id: row.get(0)?, + workspace_id: row.get(1)?, + file_path: row.get(2)?, + workspace_status: row.get(3)?, + is_untracked: row.get::<_, i64>(4)? != 0, + hunks_json: row.get(5)?, + updated_at: row.get(6)?, + }) + }) + .map_err(|e| format!("Failed to query cached changes: {}", e))?; + + changes + .collect::, _>>() + .map_err(|e| e.to_string()) +} + +/// Batch update all changed files for a workspace (replaces all) +pub fn sync_workspace_changes( + repo_path: &str, + workspace_id: Option, + changes: Vec, +) -> Result<(), String> { + let mut conn = get_connection(repo_path)?; + let tx = conn + .transaction() + .map_err(|e| format!("Failed to start transaction: {}", e))?; + + // Delete existing entries for this workspace + tx.execute( + "DELETE FROM changed_files WHERE workspace_id IS ?1", + params![workspace_id], + ) + .map_err(|e| format!("Failed to delete existing changes: {}", e))?; + + // Insert new entries + for change in &changes { + tx.execute( + "INSERT INTO changed_files + (workspace_id, file_path, workspace_status, is_untracked, hunks_json, updated_at) + VALUES (?1, ?2, ?3, ?4, ?5, ?6)", + params![ + workspace_id, + &change.file_path, + &change.workspace_status, + if change.is_untracked { 1 } else { 0 }, + &change.hunks_json, + &change.updated_at, + ], + ) + .map_err(|e| format!("Failed to insert change: {}", e))?; + } + + tx.commit() + .map_err(|e| format!("Failed to commit transaction: {}", e))?; + + Ok(()) +} + +// ============================================================================ +// Workspace Files Cache Functions +// ============================================================================ + +/// Get cached directory listing for a specific parent path +pub fn get_cached_directory_listing( + repo_path: &str, + workspace_id: Option, + parent_path: &str, +) -> Result, String> { + let conn = get_connection(repo_path)?; + let mut stmt = conn + .prepare( + "SELECT id, workspace_id, file_path, relative_path, is_directory, parent_path, cached_at, mtime + FROM workspace_files + WHERE workspace_id IS ?1 AND parent_path IS ?2 + ORDER BY is_directory DESC, relative_path", + ) + .map_err(|e| format!("Failed to prepare query: {}", e))?; + + let files = stmt + .query_map(params![workspace_id, parent_path], |row| { + Ok(CachedWorkspaceFile { + id: row.get(0)?, + workspace_id: row.get(1)?, + file_path: row.get(2)?, + relative_path: row.get(3)?, + is_directory: row.get::<_, i64>(4)? != 0, + parent_path: row.get(5)?, + cached_at: row.get(6)?, + mtime: row.get(7)?, + }) + }) + .map_err(|e| format!("Failed to query cached files: {}", e))?; + + files + .collect::, _>>() + .map_err(|e| e.to_string()) +} + +/// Batch update all cached files for a workspace (replaces all) +pub fn sync_workspace_files( + repo_path: &str, + workspace_id: Option, + files: Vec, +) -> Result<(), String> { + let mut conn = get_connection(repo_path)?; + let tx = conn + .transaction() + .map_err(|e| format!("Failed to start transaction: {}", e))?; + + // Delete existing entries for this workspace + tx.execute( + "DELETE FROM workspace_files WHERE workspace_id IS ?1", + params![workspace_id], + ) + .map_err(|e| format!("Failed to delete existing files: {}", e))?; + + // Insert new entries + for file in &files { + tx.execute( + "INSERT INTO workspace_files + (workspace_id, file_path, relative_path, is_directory, parent_path, cached_at, mtime) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)", + params![ + workspace_id, + &file.file_path, + &file.relative_path, + if file.is_directory { 1 } else { 0 }, + &file.parent_path, + &file.cached_at, + &file.mtime, + ], + ) + .map_err(|e| format!("Failed to insert file: {}", e))?; + } + + tx.commit() + .map_err(|e| format!("Failed to commit transaction: {}", e))?; + + Ok(()) +} + +/// Upsert a single workspace file (for incremental updates) +pub fn upsert_workspace_file( + repo_path: &str, + workspace_id: Option, + file_path: &str, + relative_path: &str, + is_directory: bool, + parent_path: Option<&str>, + mtime: Option, +) -> Result<(), String> { + let conn = get_connection(repo_path)?; + let cached_at = Utc::now().to_rfc3339(); + + conn.execute( + "INSERT INTO workspace_files (workspace_id, file_path, relative_path, is_directory, parent_path, cached_at, mtime) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7) + ON CONFLICT(workspace_id, file_path) + DO UPDATE SET relative_path = ?3, is_directory = ?4, parent_path = ?5, cached_at = ?6, mtime = ?7", + params![ + workspace_id, + file_path, + relative_path, + if is_directory { 1 } else { 0 }, + parent_path, + cached_at, + mtime, + ], + ) + .map_err(|e| format!("Failed to upsert workspace file: {}", e))?; + + Ok(()) +} + +/// Delete specific workspace files by paths (for incremental updates when files are deleted) +pub fn delete_workspace_files( + repo_path: &str, + workspace_id: Option, + file_paths: Vec, +) -> Result<(), String> { + if file_paths.is_empty() { + return Ok(()); + } + + let mut conn = get_connection(repo_path)?; + let tx = conn + .transaction() + .map_err(|e| format!("Failed to start transaction: {}", e))?; + + for file_path in &file_paths { + tx.execute( + "DELETE FROM workspace_files WHERE workspace_id IS ?1 AND file_path = ?2", + params![workspace_id, file_path], + ) + .map_err(|e| format!("Failed to delete file: {}", e))?; + } + + tx.commit() + .map_err(|e| format!("Failed to commit transaction: {}", e))?; + + Ok(()) +} + +/// Invalidate (clear) all cached files for a workspace +pub fn invalidate_workspace_files( + repo_path: &str, + workspace_id: Option, +) -> Result<(), String> { + let conn = get_connection(repo_path)?; + conn.execute( + "DELETE FROM workspace_files WHERE workspace_id IS ?1", + params![workspace_id], + ) + .map_err(|e| format!("Failed to invalidate workspace files: {}", e))?; + Ok(()) +} diff --git a/src-tauri/src/plan_storage.rs b/src-tauri/src/plan_storage.rs deleted file mode 100644 index db4bd003..00000000 --- a/src-tauri/src/plan_storage.rs +++ /dev/null @@ -1,141 +0,0 @@ -use serde::{Deserialize, Serialize}; -use std::fs; -use std::path::{Path, PathBuf}; - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct PlanMetadata { - pub id: String, - pub title: String, - pub plan_type: String, - pub workspace_id: Option, - pub workspace_path: Option, - pub branch_name: Option, - pub timestamp: String, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct PlanFile { - pub id: String, - pub title: String, - #[serde(rename = "type")] - pub plan_type: String, - pub raw_markdown: String, - pub workspace_id: Option, - pub workspace_path: Option, - pub branch_name: Option, - pub timestamp: String, -} - -/// Get the .treq/plans directory path for a repository -fn get_plans_dir(repo_path: &str) -> PathBuf { - Path::new(repo_path).join(".treq").join("plans") -} - -/// Ensure the .treq/plans directory exists -fn ensure_plans_dir(repo_path: &str) -> Result { - let plans_dir = get_plans_dir(repo_path); - fs::create_dir_all(&plans_dir) - .map_err(|e| format!("Failed to create plans directory: {}", e))?; - Ok(plans_dir) -} - -/// Save a plan to a file in .treq/plans/ -pub fn save_plan_to_file( - repo_path: &str, - plan_id: &str, - content: &str, - metadata: PlanMetadata, -) -> Result<(), String> { - let plans_dir = ensure_plans_dir(repo_path)?; - let plan_file_path = plans_dir.join(format!("plan_{}.json", plan_id)); - - let plan_file = PlanFile { - id: plan_id.to_string(), - title: metadata.title, - plan_type: metadata.plan_type, - raw_markdown: content.to_string(), - workspace_id: metadata.workspace_id, - workspace_path: metadata.workspace_path, - branch_name: metadata.branch_name, - timestamp: metadata.timestamp, - }; - - let json_content = serde_json::to_string_pretty(&plan_file) - .map_err(|e| format!("Failed to serialize plan: {}", e))?; - - fs::write(&plan_file_path, json_content) - .map_err(|e| format!("Failed to write plan file: {}", e))?; - - Ok(()) -} - -/// Load all plans from .treq/plans/ -pub fn load_plans_from_files(repo_path: &str) -> Result, String> { - let plans_dir = get_plans_dir(repo_path); - - // If directory doesn't exist, return empty vec - if !plans_dir.exists() { - return Ok(Vec::new()); - } - - let mut plans = Vec::new(); - - let entries = - fs::read_dir(&plans_dir).map_err(|e| format!("Failed to read plans directory: {}", e))?; - - for entry in entries { - let entry = entry.map_err(|e| format!("Failed to read directory entry: {}", e))?; - let path = entry.path(); - - // Only process .json files that start with "plan_" - if path.is_file() { - if let Some(file_name) = path.file_name().and_then(|n| n.to_str()) { - if file_name.starts_with("plan_") && file_name.ends_with(".json") { - match fs::read_to_string(&path) { - Ok(content) => match serde_json::from_str::(&content) { - Ok(plan) => plans.push(plan), - Err(e) => eprintln!("Failed to parse plan file {}: {}", file_name, e), - }, - Err(e) => eprintln!("Failed to read plan file {}: {}", file_name, e), - } - } - } - } - } - - // Sort by timestamp (newest first) - plans.sort_by(|a, b| b.timestamp.cmp(&a.timestamp)); - - Ok(plans) -} - -/// Get a specific plan file -pub fn get_plan_file(repo_path: &str, plan_id: &str) -> Result { - let plans_dir = get_plans_dir(repo_path); - let plan_file_path = plans_dir.join(format!("plan_{}.json", plan_id)); - - if !plan_file_path.exists() { - return Err(format!("Plan file not found: {}", plan_id)); - } - - let content = fs::read_to_string(&plan_file_path) - .map_err(|e| format!("Failed to read plan file: {}", e))?; - - let plan = serde_json::from_str::(&content) - .map_err(|e| format!("Failed to parse plan file: {}", e))?; - - Ok(plan) -} - -/// Delete a plan file -pub fn delete_plan_file(repo_path: &str, plan_id: &str) -> Result<(), String> { - let plans_dir = get_plans_dir(repo_path); - let plan_file_path = plans_dir.join(format!("plan_{}.json", plan_id)); - - if plan_file_path.exists() { - fs::remove_file(&plan_file_path) - .map_err(|e| format!("Failed to delete plan file: {}", e))?; - } - - Ok(()) -} diff --git a/src/App.tsx b/src/App.tsx index a3cfb88a..52a30205 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,7 +4,9 @@ import { ToastProvider } from "./components/ui/toast"; import { ThemeProvider } from "./hooks/useTheme"; import { TerminalSettingsProvider } from "./hooks/useTerminalSettings"; import { DiffSettingsProvider } from "./hooks/useDiffSettings"; +import { useSettingsPreloader } from "./hooks/useSettingsPreloader"; import { ErrorBoundary } from "./components/ErrorBoundary"; +import { PrismThemeLoader } from "./components/PrismThemeLoader"; import "./index.css"; const queryClient = new QueryClient({ @@ -16,25 +18,35 @@ const queryClient = new QueryClient({ }, }); +function AppContent() { + // Pre-load all settings in a single batch request + useSettingsPreloader(); + + return ( +
+ { + if (typeof window !== "undefined") { + window.location.reload(); + } + }} + > + + +
+ ); +} + function App() { return ( + -
- { - if (typeof window !== "undefined") { - window.location.reload(); - } - }} - > - - -
+
diff --git a/src/components/AnnotatableDiffViewer.tsx b/src/components/AnnotatableDiffViewer.tsx index 9c650656..d7b99ba0 100644 --- a/src/components/AnnotatableDiffViewer.tsx +++ b/src/components/AnnotatableDiffViewer.tsx @@ -1,11 +1,47 @@ import { useCallback, useEffect, useMemo, useRef, useState, memo } from "react"; -import type { BranchDiffFileDiff, BranchDiffHunk, DiffLineKind } from "../lib/api"; -import type { ReviewComment } from "./MergeReviewPage"; import { cn } from "../lib/utils"; import { Textarea } from "./ui/textarea"; import { Button } from "./ui/button"; import { MessageCircle, Loader2, X } from "lucide-react"; +// Type definitions - Git API removed, needs JJ equivalent +type DiffLineKind = "context" | "addition" | "deletion" | "meta"; + +export interface ReviewComment { + id: string; + filePath: string; + lineKey: string; + lineLabel: string; + kind: DiffLineKind; + oldLine?: number | null; + newLine?: number | null; + lineText: string; + text: string; + contextBefore: string[]; + contextAfter: string[]; + createdAt: string; +} + +interface BranchDiffHunk { + id: string; + header: string; + lines: Array<{ + kind: DiffLineKind; + text: string; + old_line?: number | null; + new_line?: number | null; + }>; +} + +interface BranchDiffFileDiff { + path: string; + status: string; + is_binary?: boolean; + binary_message?: string; + hunks?: BranchDiffHunk[]; + metadata?: any; +} + export interface CommentInput { filePath: string; lineKey: string; @@ -40,16 +76,16 @@ interface DraftState { } const lineKindStyles: Record = { + context: "bg-transparent", addition: "bg-green-500/10", deletion: "bg-red-500/10", - context: "bg-transparent", meta: "bg-muted/40", }; const lineKindPrefix: Record = { + context: " ", addition: "+", deletion: "-", - context: " ", meta: " ", }; @@ -161,27 +197,43 @@ const AnnotatableDiffViewerComponent: React.FC = ({ } }, [diff, selectedCommentId, fileComments]); - const buildContext = ( - lines: BranchDiffHunk["lines"], - index: number, - radius: number - ) => { - const before: string[] = []; - const after: string[] = []; - for (let offset = radius; offset > 0; offset -= 1) { - const line = lines[index - offset]; - if (line) { - before.push(`${lineKindPrefix[line.kind]}${line.content}`); + // Pre-compute context for all lines to avoid expensive buildContext calls on every render + const linesWithContext = useMemo(() => { + if (!diff) return []; + + const buildContext = ( + lines: BranchDiffHunk["lines"], + index: number, + radius: number + ) => { + const before: string[] = []; + const after: string[] = []; + for (let offset = radius; offset > 0; offset -= 1) { + const line = lines[index - offset]; + if (line) { + before.push(`${lineKindPrefix[line.kind]}${line.text}`); + } } - } - for (let offset = 1; offset <= radius; offset += 1) { - const line = lines[index + offset]; - if (line) { - after.push(`${lineKindPrefix[line.kind]}${line.content}`); + for (let offset = 1; offset <= radius; offset += 1) { + const line = lines[index + offset]; + if (line) { + after.push(`${lineKindPrefix[line.kind]}${line.text}`); + } } - } - return { before, after }; - }; + return { before, after }; + }; + + if (!diff.hunks) return []; + + return diff.hunks.flatMap((hunk, hunkIndex) => + hunk.lines.map((line, lineIndex) => ({ + hunkIndex, + lineIndex, + line, + context: buildContext(hunk.lines, lineIndex, 3), + })) + ); + }, [diff]); const renderLineNumbers = ( lineKey: string, @@ -248,7 +300,7 @@ const AnnotatableDiffViewerComponent: React.FC = ({

{diff.path}

-

Status: {diff.status}

+

Status: {diff.status}

{diff.metadata.length > 0 && (
@@ -256,23 +308,25 @@ const AnnotatableDiffViewerComponent: React.FC = ({
)}
-
- {diff.hunks.map((hunk, hunkIndex) => ( +
+ {diff.hunks?.map((hunk, hunkIndex) => { + const hunkLines = linesWithContext.filter(item => item.hunkIndex === hunkIndex); + return (
{hunk.header}
- {hunk.lines.map((line, lineIndex) => { + {hunkLines.map((item) => { + const { line, lineIndex, context } = item; const lineKey = `${diff.path}:${hunkIndex}:${lineIndex}`; const lineLabel = formatLineLabel(line.old_line, line.new_line); - const { before, after } = buildContext(hunk.lines, lineIndex, 3); const location: DraftState = { lineKey, lineLabel, kind: line.kind, oldLine: line.old_line, newLine: line.new_line, - lineText: line.content, - contextBefore: before, - contextAfter: after, + lineText: line.text, + contextBefore: context.before, + contextAfter: context.after, }; return ( @@ -292,7 +346,7 @@ const AnnotatableDiffViewerComponent: React.FC = ({
                         {lineKindPrefix[line.kind]}
-                        {line.content || " "}
+                        {line.text || " "}
                       
{draft?.lineKey === lineKey ? (
- ))} + ); + })}
); diff --git a/src/components/BranchSwitcher.tsx b/src/components/BranchSwitcher.tsx index a9356a45..ac12e00e 100644 --- a/src/components/BranchSwitcher.tsx +++ b/src/components/BranchSwitcher.tsx @@ -1,7 +1,13 @@ import { useState, useEffect } from "react"; import { Command } from "cmdk"; import { GitBranch, Check, ArrowRight } from "lucide-react"; -import { BranchListItem, gitListBranchesDetailed, gitCheckoutBranch } from "../lib/api"; + +// Type definition - Git API removed, needs JJ equivalent +interface BranchListItem { + name: string; + is_current: boolean; + is_remote: boolean; +} interface BranchSwitcherProps { open: boolean; @@ -31,8 +37,8 @@ export const BranchSwitcher: React.FC = ({ setLoading(true); setError(null); try { - const result = await gitListBranchesDetailed(repoPath); - setBranches(result); + // TODO: Replace with JJ equivalent - gitListBranchesDetailed removed + setBranches([]); } catch (err) { setError(err instanceof Error ? err.message : String(err)); } finally { @@ -50,32 +56,8 @@ export const BranchSwitcher: React.FC = ({ setError(null); try { - // If it's a remote branch, we need to create a local tracking branch - if (branch.is_remote) { - // Extract the branch name without the remote prefix (e.g., origin/feature -> feature) - const parts = branch.name.split('/'); - const localBranchName = parts.slice(1).join('/'); // Remove the remote name - - // Check if a local branch with this name already exists - const localBranchExists = branches.some( - b => !b.is_remote && b.name === localBranchName - ); - - if (localBranchExists) { - // If local branch exists, just checkout - await gitCheckoutBranch(repoPath, localBranchName, false); - } else { - // Create a new local tracking branch - await gitCheckoutBranch(repoPath, localBranchName, true); - } - - onBranchChanged?.(localBranchName); - } else { - // For local branches, just checkout - await gitCheckoutBranch(repoPath, branch.name, false); - onBranchChanged?.(branch.name); - } - + // TODO: Replace with JJ equivalent - gitCheckoutBranch removed + onBranchChanged?.(branch.name); onOpenChange(false); } catch (err) { setError(err instanceof Error ? err.message : String(err)); @@ -134,7 +116,7 @@ export const BranchSwitcher: React.FC = ({ {groupedBranches.current.map((branch) => ( handleSelectBranch(branch)} disabled={switching} @@ -144,7 +126,7 @@ export const BranchSwitcher: React.FC = ({
{branch.name}
- current + current
))}
@@ -155,7 +137,7 @@ export const BranchSwitcher: React.FC = ({ {groupedBranches.local.map((branch) => ( handleSelectBranch(branch)} disabled={switching} @@ -175,7 +157,7 @@ export const BranchSwitcher: React.FC = ({ {groupedBranches.remote.map((branch) => ( handleSelectBranch(branch)} disabled={switching} @@ -185,7 +167,7 @@ export const BranchSwitcher: React.FC = ({
{branch.name}
- remote + remote
))}
@@ -195,13 +177,13 @@ export const BranchSwitcher: React.FC = ({ {/* Footer with keyboard hints */} -
+
↑↓ Navigate ↡ Switch Esc Close
- {switching && Switching...} + {switching && Switching...}
diff --git a/src/components/ChangesDiffViewer.tsx b/src/components/ChangesDiffViewer.tsx new file mode 100644 index 00000000..f7cd9697 --- /dev/null +++ b/src/components/ChangesDiffViewer.tsx @@ -0,0 +1,2313 @@ +import { + memo, + useCallback, + useEffect, + useMemo, + useRef, + useState, + Fragment, + forwardRef, + useImperativeHandle, +} from "react"; +import { type KeyboardEvent as ReactKeyboardEvent } from "react"; +import { openPath } from "@tauri-apps/plugin-opener"; +import { v4 as uuidv4 } from "uuid"; +import { + jjGetChangedFiles, + jjGetFileHunks, + jjRestoreFile, + jjRestoreAll, + jjCommit, + getDiffCache, + ptyWrite, + markFileViewed, + unmarkFileViewed, + type JjDiffHunk, +} from "../lib/api"; +import { useCachedWorkspaceChanges } from "../hooks/useCachedWorkspaceChanges"; +import { Button } from "./ui/button"; +import { Textarea } from "./ui/textarea"; +import { useToast } from "./ui/toast"; +import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover"; +import { + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, +} from "./ui/dropdown-menu"; +import { + AlertTriangle, + FileText, + Loader2, + Plus, + ChevronDown, + ChevronRight, + MoreVertical, + CheckCircle2, + MessageSquare, + Send, + X, + Copy, + Check, + Square, + RefreshCw, +} from "lucide-react"; +import { cn } from "../lib/utils"; +import { getLanguageFromPath, highlightCode } from "../lib/syntax-highlight"; +import { + parseJjChangedFiles, + isBinaryFile, + type ParsedFileChange, +} from "../lib/git-utils"; +import { useDiffSettings } from "../hooks/useDiffSettings"; +import { ChangesSection } from "./ChangesSection"; +import { ConflictsSection } from "./ConflictsSection"; +import { MoveToWorkspaceDialog } from "./MoveToWorkspaceDialog"; + +interface ChangesDiffViewerProps { + workspacePath: string; + readOnly?: boolean; + onStagedFilesChange?: (files: string[]) => void; + initialSelectedFile: string | null; + terminalSessionId?: string; + onReviewSubmitted?: () => void; + conflictedFiles?: string[]; +} + +export interface ChangesDiffViewerHandle { + focusCommitInput: () => void; +} + +interface LineComment { + id: string; + filePath: string; + hunkId: string; + startLine: number; // actual file line number (1-indexed) + endLine: number; // actual file line number (1-indexed) + lineContent: string[]; + text: string; + createdAt: string; +} + +// Extended line selection for staging (supports multi-hunk) +interface DiffLineSelection { + filePath: string; + lines: Array<{ + hunkIndex: number; + lineIndex: number; + content: string; + isStaged: boolean; + }>; +} + +interface FileHunksData { + filePath: string; + hunks: JjDiffHunk[]; + isLoading: boolean; + error?: string; +} + +// Helper to get line type styling (background only, text color handled by syntax highlighting) +const getLineTypeClass = (line: string): string => { + if (line.startsWith("+")) return "bg-emerald-500/10"; + if (line.startsWith("-")) return "bg-red-500/10"; + return ""; +}; + +const getLinePrefix = (line: string): string => { + if (line.startsWith("+")) return "+"; + if (line.startsWith("-")) return "-"; + return " "; +}; + +const hunksEqual = ( + a?: JjDiffHunk[] | null, + b?: JjDiffHunk[] | null +): boolean => { + if (!a && !b) return true; + if (!a || !b) return false; + if (a.length !== b.length) return false; + return JSON.stringify(a) === JSON.stringify(b); +}; + +const filesEqual = (a: ParsedFileChange[], b: ParsedFileChange[]): boolean => { + if (a.length !== b.length) return false; + for (let i = 0; i < a.length; i++) { + if ( + a[i].path !== b[i].path || + a[i].stagedStatus !== b[i].stagedStatus || + a[i].workspaceStatus !== b[i].workspaceStatus || + a[i].isUntracked !== b[i].isUntracked + ) { + return false; + } + } + return true; +}; + +const parseCachedHunks = (raw: string): JjDiffHunk[] | null => { + try { + const parsed = JSON.parse(raw); + if (Array.isArray(parsed)) { + return parsed as JjDiffHunk[]; + } + } catch { + // Silently ignore parse failures + } + return null; +}; + +// Parse hunk header to extract starting line numbers and counts +const parseHunkHeader = ( + header: string +): { + oldStart: number; + newStart: number; + oldCount: number; + newCount: number; +} => { + const match = header.match(/@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/); + if (!match) { + return { oldStart: 1, newStart: 1, oldCount: 1, newCount: 1 }; + } + return { + oldStart: parseInt(match[1], 10), + oldCount: match[2] ? parseInt(match[2], 10) : 1, + newStart: parseInt(match[3], 10), + newCount: match[4] ? parseInt(match[4], 10) : 1, + }; +}; + +// Compute actual line numbers for each line in a hunk +const computeHunkLineNumbers = ( + hunk: JjDiffHunk +): Array<{ old?: number; new?: number }> => { + const { oldStart, newStart } = parseHunkHeader(hunk.header); + let oldLine = oldStart; + let newLine = newStart; + + return hunk.lines.map((line) => { + if (line.startsWith("+")) { + return { new: newLine++ }; + } else if (line.startsWith("-")) { + return { old: oldLine++ }; + } else { + // Context line - both increment + return { old: oldLine++, new: newLine++ }; + } + }); +}; + +// Compute a simple hash of file hunks for change detection +const computeHunksHash = (hunks: JjDiffHunk[]): string => { + // Create a string from all hunk content and hash it + const content = hunks.map((h) => h.header + h.lines.join("")).join("|"); + // Simple hash function (djb2) + let hash = 5381; + for (let i = 0; i < content.length; i++) { + hash = (hash << 5) + hash + content.charCodeAt(i); + hash = hash & hash; // Convert to 32bit integer + } + return hash.toString(16); +}; + +// Isolated comment input component to prevent parent re-renders during typing +interface CommentInputProps { + onSubmit: (text: string) => void; + onCancel: () => void; + filePath?: string; + startLine?: number; + endLine?: number; +} + +const CommentInput: React.FC = memo( + ({ onSubmit, onCancel, filePath, startLine, endLine }) => { + const [text, setText] = useState(""); + + const handleSubmit = useCallback(() => { + if (text.trim()) { + onSubmit(text.trim()); + } + }, [text, onSubmit]); + + const handleKeyDown = useCallback( + (e: ReactKeyboardEvent) => { + // Stop propagation for standard text editing shortcuts + if (e.metaKey || e.ctrlKey) { + const key = e.key.toLowerCase(); + if (["a", "c", "x", "v", "z", "y"].includes(key)) { + e.stopPropagation(); + return; // Let browser handle natively + } + } + + if (e.key === "Escape") { + onCancel(); + } else if ((e.metaKey || e.ctrlKey) && e.key === "Enter") { + handleSubmit(); + } + }, + [onCancel, handleSubmit] + ); + + const lineLabel = + startLine && endLine + ? startLine === endLine + ? `L${startLine}` + : `L${startLine}-${endLine}` + : null; + + return ( +
+ {filePath && lineLabel && ( +
+ {filePath}:{lineLabel} +
+ )} +