diff --git a/.github/ISSUE_TEMPLATE/UI_issues.yml b/.github/ISSUE_TEMPLATE/UI_issues.yml index eb6e830f..c719ea20 100644 --- a/.github/ISSUE_TEMPLATE/UI_issues.yml +++ b/.github/ISSUE_TEMPLATE/UI_issues.yml @@ -1,5 +1,5 @@ -name: 🎨 UI Issue +name: UI Issue description: "Use this template if something looks weird or you would like some styles changed." title: "UI issue" labels: ["styles"] diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index df356d00..10126a0c 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,5 +1,6 @@ -name: 🐛 Bug Report +name: Bug Report description: "Create a bug report for obsidian smart second brain to help us improve" +title: "Bug report" labels: ["bug"] assignees: ["leo310", "nicobrauchtgit"] body: @@ -21,14 +22,6 @@ body: label: Error Statement description: Enable Settings > Advanced > Developer Console logging. Open Developer Tools (⌘ Cmd + ⌥ Opt + I / Ctrl + Shift + I). Open Console Tab. placeholder: Obsidian Developer Console - - type: textarea - id: steps-to-reproduce - attributes: - label: Steps to Reproduce - description: List the steps to reproduce the behavior. - placeholder: "1. Go to '...'\n2. Click on '...'\n3. Scroll down to '...'\n4. See error" - validations: - required: true - type: input id: version attributes: diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 38aca0ce..404a826f 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,5 +1,6 @@ -name: 🌟 Feature Request -description: What would you like to see added to smart second brain? 🐙 +name: Feature Request +description: What would you like to see added to smart second brain? +title: Feature Request labels: - enhancement assignees: diff --git a/.gitignore b/.gitignore index 508dfbe0..a55889d3 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,5 @@ workspace.json *.njsproj *.sln *.sw? +.envrc +.direnv/* \ No newline at end of file diff --git a/.opencode/opencode.db b/.opencode/opencode.db new file mode 100644 index 00000000..4e86411b Binary files /dev/null and b/.opencode/opencode.db differ diff --git a/.opencode/opencode.db-shm b/.opencode/opencode.db-shm new file mode 100644 index 00000000..7033e039 Binary files /dev/null and b/.opencode/opencode.db-shm differ diff --git a/.opencode/opencode.db-wal b/.opencode/opencode.db-wal new file mode 100644 index 00000000..6c0e12f0 Binary files /dev/null and b/.opencode/opencode.db-wal differ diff --git a/README.md b/README.md index 9b0f965c..094e5698 100644 --- a/README.md +++ b/README.md @@ -48,19 +48,17 @@ Follow the onboarding instructions provided on initial plugin startup in Obsidia # ⚙️ Under the hood -Check out our [Architecture Wiki](https://github.com/your-papa/obsidian-Smart2Brain/wiki) page and our backend repo [papa-ts](https://github.com/your-papa/papa-ts). +Check out our [Architecture Wiki](https://github.com/your-papa/obsidian-Smart2Brain/wiki) page. # 🎯 Roadmap -- Support Gemini and Claude models and OpenAI likes (Openrouter...) +- Support Gemini and Claude models and integrate KoboldCpp - Similar note connections view - Chat Threads -- Hybrid Vector Search (e.g. for Time-based retrieval) -- Inline AI Assistant +- Hybrid Vector Search - Predictive Note Placement - Agent with Obsidian tooling - Multimodality -- Benchmarking # 🧑‍💻 About us diff --git a/biome.json b/biome.json index eed16bc9..b07953a3 100644 --- a/biome.json +++ b/biome.json @@ -1,12 +1,25 @@ { - "$schema": "https://biomejs.dev/schemas/1.2.2/schema.json", - "organizeImports": { - "enabled": true - }, - "linter": { - "enabled": true, - "rules": { - "recommended": true - } - } + "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", + "organizeImports": { + "enabled": true + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true + } + }, + "formatter": { + "enabled": true, + "formatWithErrors": false, + "indentStyle": "tab", + "indentWidth": 4, + "lineWidth": 120 + }, + "javascript": { + "formatter": { + "semicolons": "always", + "trailingCommas": "all" + } + } } diff --git a/bun.lock b/bun.lock new file mode 100644 index 00000000..862ab8af --- /dev/null +++ b/bun.lock @@ -0,0 +1,866 @@ +{ + "lockfileVersion": 1, + "configVersion": 0, + "workspaces": { + "": { + "name": "smart-second-brain", + "dependencies": { + "@selemondev/svgl-svelte": "^0.0.3", + "@tanstack/svelte-query": "^6.0.10", + "bits-ui": "^2.11.8", + "builtin-modules": "^5.0.0", + "dexie": "^4.2.1", + "i18next": "^23.16.8", + "svelte-i18n": "^4.0.1", + "uuid": "^11.1.0", + "zod": "^4.2.1", + }, + "devDependencies": { + "@biomejs/biome": "^1.9.4", + "@langchain/langgraph-checkpoint": "^1.0.0", + "@langchain/mcp-adapters": "^1.0.2", + "@langchain/tavily": "^1.0.1", + "@sveltejs/vite-plugin-svelte": "^5.1.1", + "@tsconfig/svelte": "^5.0.5", + "autoprefixer": "^10.4.21", + "obsidian": "^1.10.0", + "postcss": "^8.5.6", + "svelte": "^5.41.0", + "svelte-check": "^4.3.3", + "tailwindcss": "^3.4.18", + "tslib": "^2.8.1", + "typescript": "^5.9.3", + "vite": "^7.0.0", + }, + }, + }, + "packages": { + "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], + + "@babel/runtime": ["@babel/runtime@7.27.6", "", {}, "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q=="], + + "@biomejs/biome": ["@biomejs/biome@1.9.4", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "1.9.4", "@biomejs/cli-darwin-x64": "1.9.4", "@biomejs/cli-linux-arm64": "1.9.4", "@biomejs/cli-linux-arm64-musl": "1.9.4", "@biomejs/cli-linux-x64": "1.9.4", "@biomejs/cli-linux-x64-musl": "1.9.4", "@biomejs/cli-win32-arm64": "1.9.4", "@biomejs/cli-win32-x64": "1.9.4" }, "bin": { "biome": "bin/biome" } }, "sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog=="], + + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@1.9.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw=="], + + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@1.9.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg=="], + + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g=="], + + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA=="], + + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg=="], + + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg=="], + + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@1.9.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg=="], + + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@1.9.4", "", { "os": "win32", "cpu": "x64" }, "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA=="], + + "@cfworker/json-schema": ["@cfworker/json-schema@4.1.1", "", {}, "sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og=="], + + "@codemirror/state": ["@codemirror/state@6.5.2", "", { "dependencies": { "@marijn/find-cluster-break": "^1.0.0" } }, "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA=="], + + "@codemirror/view": ["@codemirror/view@6.37.1", "", { "dependencies": { "@codemirror/state": "^6.5.0", "crelt": "^1.0.6", "style-mod": "^4.1.0", "w3c-keyname": "^2.2.4" } }, "sha512-Qy4CAUwngy/VQkEz0XzMKVRcckQuqLYWKqVpDDDghBe5FSXSqfVrJn49nw3ePZHxRUz4nRmb05Lgi+9csWo4eg=="], + + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.5", "", { "os": "android", "cpu": "arm" }, "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.5", "", { "os": "android", "cpu": "arm64" }, "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.5", "", { "os": "android", "cpu": "x64" }, "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.5", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.5", "", { "os": "linux", "cpu": "arm" }, "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.5", "", { "os": "linux", "cpu": "ia32" }, "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.5", "", { "os": "linux", "cpu": "none" }, "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.5", "", { "os": "linux", "cpu": "none" }, "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.5", "", { "os": "linux", "cpu": "none" }, "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.5", "", { "os": "linux", "cpu": "x64" }, "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.5", "", { "os": "none", "cpu": "arm64" }, "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.5", "", { "os": "none", "cpu": "x64" }, "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.5", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.5", "", { "os": "openbsd", "cpu": "x64" }, "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.5", "", { "os": "sunos", "cpu": "x64" }, "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.5", "", { "os": "win32", "cpu": "x64" }, "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g=="], + + "@floating-ui/core": ["@floating-ui/core@1.7.3", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w=="], + + "@floating-ui/dom": ["@floating-ui/dom@1.7.4", "", { "dependencies": { "@floating-ui/core": "^1.7.3", "@floating-ui/utils": "^0.2.10" } }, "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA=="], + + "@floating-ui/utils": ["@floating-ui/utils@0.2.10", "", {}, "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ=="], + + "@formatjs/ecma402-abstract": ["@formatjs/ecma402-abstract@2.3.4", "", { "dependencies": { "@formatjs/fast-memoize": "2.2.7", "@formatjs/intl-localematcher": "0.6.1", "decimal.js": "^10.4.3", "tslib": "^2.8.0" } }, "sha512-qrycXDeaORzIqNhBOx0btnhpD1c+/qFIHAN9znofuMJX6QBwtbrmlpWfD4oiUUD2vJUOIYFA/gYtg2KAMGG7sA=="], + + "@formatjs/fast-memoize": ["@formatjs/fast-memoize@2.2.7", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ=="], + + "@formatjs/icu-messageformat-parser": ["@formatjs/icu-messageformat-parser@2.11.2", "", { "dependencies": { "@formatjs/ecma402-abstract": "2.3.4", "@formatjs/icu-skeleton-parser": "1.8.14", "tslib": "^2.8.0" } }, "sha512-AfiMi5NOSo2TQImsYAg8UYddsNJ/vUEv/HaNqiFjnI3ZFfWihUtD5QtuX6kHl8+H+d3qvnE/3HZrfzgdWpsLNA=="], + + "@formatjs/icu-skeleton-parser": ["@formatjs/icu-skeleton-parser@1.8.14", "", { "dependencies": { "@formatjs/ecma402-abstract": "2.3.4", "tslib": "^2.8.0" } }, "sha512-i4q4V4qslThK4Ig8SxyD76cp3+QJ3sAqr7f6q9VVfeGtxG9OhiAk3y9XF6Q41OymsKzsGQ6OQQoJNY4/lI8TcQ=="], + + "@formatjs/intl-localematcher": ["@formatjs/intl-localematcher@0.6.1", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-ePEgLgVCqi2BBFnTMWPfIghu6FkbZnnBVhO2sSxvLfrdFw7wCHAHiDoM2h4NRgjbaY7+B7HgOLZGkK187pZTZg=="], + + "@internationalized/date": ["@internationalized/date@3.9.0", "", { "dependencies": { "@swc/helpers": "^0.5.0" } }, "sha512-yaN3brAnHRD+4KyyOsJyk49XUvj2wtbNACSqg0bz3u8t2VuzhC8Q5dfRnrSxjnnbDb+ienBnkn1TzQfE154vyg=="], + + "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "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" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], + + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="], + + "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], + + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + + "@jridgewell/set-array": ["@jridgewell/set-array@1.2.1", "", {}, "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="], + + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="], + + "@langchain/core": ["@langchain/core@1.1.6", "", { "dependencies": { "@cfworker/json-schema": "^4.0.2", "ansi-styles": "^5.0.0", "camelcase": "6", "decamelize": "1.2.0", "js-tiktoken": "^1.0.12", "langsmith": "^0.3.82", "mustache": "^4.2.0", "p-queue": "^6.6.2", "uuid": "^10.0.0", "zod": "^3.25.76 || ^4" } }, "sha512-db5H+nLb6rwTW7noIlspN9nDi8b6NeuRWpelzS3+/BuasrJlZ6QbTDxkIqJRTEyLB2av3xOHlYHNmDHKal0XYA=="], + + "@langchain/langgraph": ["@langchain/langgraph@1.0.7", "", { "dependencies": { "@langchain/langgraph-checkpoint": "^1.0.0", "@langchain/langgraph-sdk": "~1.3.1", "uuid": "^10.0.0" }, "peerDependencies": { "@langchain/core": "^1.0.1", "zod": "^3.25.32 || ^4.1.0", "zod-to-json-schema": "^3.x" }, "optionalPeers": ["zod-to-json-schema"] }, "sha512-EBGqNOWoRiEoLUaeuiXRpUM8/DE6QcwiirNyd97XhezStebBoTTilWH8CUt6S94JRGl5zwfBBRHfzotDnZS/eA=="], + + "@langchain/langgraph-checkpoint": ["@langchain/langgraph-checkpoint@1.0.0", "", { "dependencies": { "uuid": "^10.0.0" }, "peerDependencies": { "@langchain/core": "^1.0.1" } }, "sha512-xrclBGvNCXDmi0Nz28t3vjpxSH6UYx6w5XAXSiiB1WEdc2xD2iY/a913I3x3a31XpInUW/GGfXXfePfaghV54A=="], + + "@langchain/langgraph-sdk": ["@langchain/langgraph-sdk@1.3.1", "", { "dependencies": { "p-queue": "^6.6.2", "p-retry": "4", "uuid": "^9.0.0" }, "peerDependencies": { "@langchain/core": "^1.0.1", "react": "^18 || ^19", "react-dom": "^18 || ^19" }, "optionalPeers": ["@langchain/core", "react", "react-dom"] }, "sha512-zTi7DZHwqtMEzapvm3I1FL4Q7OZsxtq9tTXy6s2gcCxyIU3sphqRboqytqVN7dNHLdTCLb8nXy49QKurs2MIBg=="], + + "@langchain/mcp-adapters": ["@langchain/mcp-adapters@1.1.0", "", { "dependencies": { "@modelcontextprotocol/sdk": "~1.19.1", "debug": "^4.4.3", "zod": "^3.25.76 || ^4" }, "optionalDependencies": { "extended-eventsource": "^1.7.0" }, "peerDependencies": { "@langchain/core": "^1.0.0", "@langchain/langgraph": "^1.0.0" } }, "sha512-961bufgmlLBWSJ3kA1vJbocM1v678D6a4e/NXOxE4KsSslpJZvaz5XmTmpHa5XBM5wKcUOjDdJdvLuOC2Pw5KQ=="], + + "@langchain/tavily": ["@langchain/tavily@1.1.0", "", { "dependencies": { "zod": "^3.25.76 || ^4" }, "peerDependencies": { "@langchain/core": "^1.0.0" } }, "sha512-RkvBT//wMioKM3O8LrlvzweYJFL6Srhdz0cjVTodZsxQy0FedJ5DQXJ36Ul/11bRES1Oe/XOW8vT7D+fSxJ92Q=="], + + "@marijn/find-cluster-break": ["@marijn/find-cluster-break@1.0.2", "", {}, "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g=="], + + "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.19.1", "", { "dependencies": { "ajv": "^6.12.6", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-3Y2h3MZKjec1eAqSTBclATlX+AbC6n1LgfVzRMJLt3v6w0RCYgwLrjbxPDbhsYHt6Wdqc/aCceNJYgj448ELQQ=="], + + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], + + "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], + + "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], + + "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], + + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.53.3", "", { "os": "android", "cpu": "arm" }, "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w=="], + + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.53.3", "", { "os": "android", "cpu": "arm64" }, "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w=="], + + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.53.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA=="], + + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.53.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ=="], + + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.53.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w=="], + + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.53.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q=="], + + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.53.3", "", { "os": "linux", "cpu": "arm" }, "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw=="], + + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.53.3", "", { "os": "linux", "cpu": "arm" }, "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg=="], + + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.53.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w=="], + + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.53.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A=="], + + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.53.3", "", { "os": "linux", "cpu": "none" }, "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g=="], + + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.53.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw=="], + + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.53.3", "", { "os": "linux", "cpu": "none" }, "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g=="], + + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.53.3", "", { "os": "linux", "cpu": "none" }, "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A=="], + + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.53.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg=="], + + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.53.3", "", { "os": "linux", "cpu": "x64" }, "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w=="], + + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.53.3", "", { "os": "linux", "cpu": "x64" }, "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q=="], + + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.53.3", "", { "os": "none", "cpu": "arm64" }, "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw=="], + + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.53.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw=="], + + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.53.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA=="], + + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.53.3", "", { "os": "win32", "cpu": "x64" }, "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg=="], + + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.53.3", "", { "os": "win32", "cpu": "x64" }, "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ=="], + + "@selemondev/svgl-svelte": ["@selemondev/svgl-svelte@0.0.3", "", { "peerDependencies": { "svelte": "^5.0.0" } }, "sha512-86WAfU6MaMrC2uLU+LhfQoH7et4dJye58jcJCaLtHsB2vNpzKslA6evveAZ+w0Pf29yr9oT0TNChjo4OQLTikQ=="], + + "@sveltejs/acorn-typescript": ["@sveltejs/acorn-typescript@1.0.5", "", { "peerDependencies": { "acorn": "^8.9.0" } }, "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ=="], + + "@sveltejs/vite-plugin-svelte": ["@sveltejs/vite-plugin-svelte@5.1.1", "", { "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", "debug": "^4.4.1", "deepmerge": "^4.3.1", "kleur": "^4.1.5", "magic-string": "^0.30.17", "vitefu": "^1.0.6" }, "peerDependencies": { "svelte": "^5.0.0", "vite": "^6.0.0" } }, "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ=="], + + "@sveltejs/vite-plugin-svelte-inspector": ["@sveltejs/vite-plugin-svelte-inspector@4.0.1", "", { "dependencies": { "debug": "^4.3.7" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^5.0.0", "svelte": "^5.0.0", "vite": "^6.0.0" } }, "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw=="], + + "@swc/helpers": ["@swc/helpers@0.5.17", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A=="], + + "@tanstack/query-core": ["@tanstack/query-core@5.90.12", "", {}, "sha512-T1/8t5DhV/SisWjDnaiU2drl6ySvsHj1bHBCWNXd+/T+Hh1cf6JodyEYMd5sgwm+b/mETT4EV3H+zCVczCU5hg=="], + + "@tanstack/svelte-query": ["@tanstack/svelte-query@6.0.10", "", { "dependencies": { "@tanstack/query-core": "5.90.12" }, "peerDependencies": { "svelte": "^5.25.0" } }, "sha512-J0kM3JNvRcRCM6cbHLeICs73aLp98N/nsihdVEtiNo3MEN4pAnO45qZ2yxX70MrEZ9vffXaCXMCChwgXs1lZ/Q=="], + + "@tsconfig/svelte": ["@tsconfig/svelte@5.0.5", "", {}, "sha512-48fAnUjKye38FvMiNOj0J9I/4XlQQiZlpe9xaNPfe8vy2Y1hFBt8g1yqf2EGjVvHavo4jf2lC+TQyENCr4BJBQ=="], + + "@types/codemirror": ["@types/codemirror@5.60.8", "", { "dependencies": { "@types/tern": "*" } }, "sha512-VjFgDF/eB+Aklcy15TtOTLQeMjTo07k7KAjql8OK5Dirr7a6sJY4T1uVBDuTVG9VEmn1uUsohOpYnVfgC6/jyw=="], + + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + + "@types/node": ["@types/node@25.0.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-gWEkeiyYE4vqjON/+Obqcoeffmk0NF15WSBwSs7zwVA2bAbTaE0SJ7P0WNGoJn8uE7fiaV5a7dKYIJriEqOrmA=="], + + "@types/retry": ["@types/retry@0.12.0", "", {}, "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA=="], + + "@types/tern": ["@types/tern@0.23.9", "", { "dependencies": { "@types/estree": "*" } }, "sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw=="], + + "@types/uuid": ["@types/uuid@10.0.0", "", {}, "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ=="], + + "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], + + "acorn": ["acorn@8.14.1", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg=="], + + "ajv": ["ajv@6.12.6", "", { "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" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], + + "ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="], + + "ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], + + "any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="], + + "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], + + "arg": ["arg@5.0.2", "", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="], + + "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="], + + "autoprefixer": ["autoprefixer@10.4.21", "", { "dependencies": { "browserslist": "^4.24.4", "caniuse-lite": "^1.0.30001702", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": { "autoprefixer": "bin/autoprefixer" } }, "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ=="], + + "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], + + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + + "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], + + "bits-ui": ["bits-ui@2.11.8", "", { "dependencies": { "@floating-ui/core": "^1.7.1", "@floating-ui/dom": "^1.7.1", "esm-env": "^1.1.2", "runed": "^0.35.1", "svelte-toolbelt": "^0.10.6", "tabbable": "^6.2.0" }, "peerDependencies": { "@internationalized/date": "^3.8.1", "svelte": "^5.33.0" } }, "sha512-zsgVH2iozBywIPJ7iF0fgp+23pGRGj0FyC9uFL4oZ83hhfaN5IEEkED7UtEf5LAjczc67zlmOIxwTRFBKvFX/Q=="], + + "body-parser": ["body-parser@2.2.1", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw=="], + + "brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], + + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], + + "browserslist": ["browserslist@4.25.0", "", { "dependencies": { "caniuse-lite": "^1.0.30001718", "electron-to-chromium": "^1.5.160", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA=="], + + "builtin-modules": ["builtin-modules@5.0.0", "", {}, "sha512-bkXY9WsVpY7CvMhKSR6pZilZu9Ln5WDrKVBUXf2S443etkmEO4V58heTecXcUIsNsi4Rx8JUO4NfX1IcQl4deg=="], + + "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], + + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + + "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], + + "camelcase": ["camelcase@6.3.0", "", {}, "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="], + + "camelcase-css": ["camelcase-css@2.0.1", "", {}, "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="], + + "caniuse-lite": ["caniuse-lite@1.0.30001721", "", {}, "sha512-cOuvmUVtKrtEaoKiO0rSc29jcjwMwX5tOHDy4MgVFEWiUXj4uBMJkwI8MDySkgXidpMiHUcviogAvFi4pA2hDQ=="], + + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], + + "cli-color": ["cli-color@2.0.4", "", { "dependencies": { "d": "^1.0.1", "es5-ext": "^0.10.64", "es6-iterator": "^2.0.3", "memoizee": "^0.4.15", "timers-ext": "^0.1.7" } }, "sha512-zlnpg0jNcibNrO7GG9IeHH7maWFeCz+Ja1wx/7tZNU5ASSSSZ+/qZciM0/LHCYxSdqv5h2sdbQ/PXYdOuetXvA=="], + + "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], + + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], + + "console-table-printer": ["console-table-printer@2.15.0", "", { "dependencies": { "simple-wcswidth": "^1.1.2" } }, "sha512-SrhBq4hYVjLCkBVOWaTzceJalvn5K1Zq5aQA6wXC/cYjI3frKWNPEMK3sZsJfNNQApvCQmgBcc13ZKmFj8qExw=="], + + "content-disposition": ["content-disposition@1.0.1", "", {}, "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q=="], + + "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], + + "cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], + + "cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="], + + "cors": ["cors@2.8.5", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g=="], + + "crelt": ["crelt@1.0.6", "", {}, "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g=="], + + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], + + "d": ["d@1.0.2", "", { "dependencies": { "es5-ext": "^0.10.64", "type": "^2.7.2" } }, "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "decamelize": ["decamelize@1.2.0", "", {}, "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA=="], + + "decimal.js": ["decimal.js@10.5.0", "", {}, "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw=="], + + "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="], + + "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], + + "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], + + "dexie": ["dexie@4.2.1", "", {}, "sha512-Ckej0NS6jxQ4Po3OrSQBFddayRhTCic2DoCAG5zacOfOVB9P2Q5Xc5uL/nVa7ZVs+HdMnvUPzLFCB/JwpB6Csg=="], + + "didyoumean": ["didyoumean@1.2.2", "", {}, "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="], + + "dlv": ["dlv@1.1.3", "", {}, "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="], + + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + + "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], + + "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], + + "electron-to-chromium": ["electron-to-chromium@1.5.165", "", {}, "sha512-naiMx1Z6Nb2TxPU6fiFrUrDTjyPMLdTtaOd2oLmG8zVSg2hCWGkhPyxwk+qRmZ1ytwVqUv0u7ZcDA5+ALhaUtw=="], + + "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + + "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], + + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + + "es5-ext": ["es5-ext@0.10.64", "", { "dependencies": { "es6-iterator": "^2.0.3", "es6-symbol": "^3.1.3", "esniff": "^2.0.1", "next-tick": "^1.1.0" } }, "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg=="], + + "es6-iterator": ["es6-iterator@2.0.3", "", { "dependencies": { "d": "1", "es5-ext": "^0.10.35", "es6-symbol": "^3.1.1" } }, "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g=="], + + "es6-symbol": ["es6-symbol@3.1.4", "", { "dependencies": { "d": "^1.0.2", "ext": "^1.7.0" } }, "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg=="], + + "es6-weak-map": ["es6-weak-map@2.0.3", "", { "dependencies": { "d": "1", "es5-ext": "^0.10.46", "es6-iterator": "^2.0.3", "es6-symbol": "^3.1.1" } }, "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA=="], + + "esbuild": ["esbuild@0.25.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.5", "@esbuild/android-arm": "0.25.5", "@esbuild/android-arm64": "0.25.5", "@esbuild/android-x64": "0.25.5", "@esbuild/darwin-arm64": "0.25.5", "@esbuild/darwin-x64": "0.25.5", "@esbuild/freebsd-arm64": "0.25.5", "@esbuild/freebsd-x64": "0.25.5", "@esbuild/linux-arm": "0.25.5", "@esbuild/linux-arm64": "0.25.5", "@esbuild/linux-ia32": "0.25.5", "@esbuild/linux-loong64": "0.25.5", "@esbuild/linux-mips64el": "0.25.5", "@esbuild/linux-ppc64": "0.25.5", "@esbuild/linux-riscv64": "0.25.5", "@esbuild/linux-s390x": "0.25.5", "@esbuild/linux-x64": "0.25.5", "@esbuild/netbsd-arm64": "0.25.5", "@esbuild/netbsd-x64": "0.25.5", "@esbuild/openbsd-arm64": "0.25.5", "@esbuild/openbsd-x64": "0.25.5", "@esbuild/sunos-x64": "0.25.5", "@esbuild/win32-arm64": "0.25.5", "@esbuild/win32-ia32": "0.25.5", "@esbuild/win32-x64": "0.25.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ=="], + + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + + "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], + + "esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="], + + "esniff": ["esniff@2.0.1", "", { "dependencies": { "d": "^1.0.1", "es5-ext": "^0.10.62", "event-emitter": "^0.3.5", "type": "^2.7.2" } }, "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg=="], + + "esrap": ["esrap@2.1.0", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" } }, "sha512-yzmPNpl7TBbMRC5Lj2JlJZNPml0tzqoqP5B1JXycNUwtqma9AKCO0M2wHrdgsHcy1WRW7S9rJknAMtByg3usgA=="], + + "estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], + + "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], + + "event-emitter": ["event-emitter@0.3.5", "", { "dependencies": { "d": "1", "es5-ext": "~0.10.14" } }, "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA=="], + + "eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="], + + "eventsource": ["eventsource@3.0.7", "", { "dependencies": { "eventsource-parser": "^3.0.1" } }, "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA=="], + + "eventsource-parser": ["eventsource-parser@3.0.6", "", {}, "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg=="], + + "express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="], + + "express-rate-limit": ["express-rate-limit@7.5.1", "", { "peerDependencies": { "express": ">= 4.11" } }, "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw=="], + + "ext": ["ext@1.7.0", "", { "dependencies": { "type": "^2.7.2" } }, "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw=="], + + "extended-eventsource": ["extended-eventsource@1.7.0", "", {}, "sha512-s8rtvZuYcKBpzytHb5g95cHbZ1J99WeMnV18oKc5wKoxkHzlzpPc/bNAm7Da2Db0BDw0CAu1z3LpH+7UsyzIpw=="], + + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + + "fast-glob": ["fast-glob@3.3.3", "", { "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" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], + + "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], + + "fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="], + + "fdir": ["fdir@6.4.5", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw=="], + + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + + "finalhandler": ["finalhandler@2.1.1", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA=="], + + "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], + + "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], + + "fraction.js": ["fraction.js@4.3.7", "", {}, "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew=="], + + "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + + "glob": ["glob@10.4.5", "", { "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" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], + + "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], + + "globalyzer": ["globalyzer@0.1.0", "", {}, "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q=="], + + "globrex": ["globrex@0.1.2", "", {}, "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg=="], + + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + + "http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="], + + "i18next": ["i18next@23.16.8", "", { "dependencies": { "@babel/runtime": "^7.23.2" } }, "sha512-06r/TitrM88Mg5FdUXAKL96dJMzgqLE5dv3ryBAra4KCwD9mJ4ndOTS95ZuymIGoE+2hzfdaMak2X11/es7ZWg=="], + + "iconv-lite": ["iconv-lite@0.7.1", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw=="], + + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + + "inline-style-parser": ["inline-style-parser@0.2.4", "", {}, "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q=="], + + "intl-messageformat": ["intl-messageformat@10.7.16", "", { "dependencies": { "@formatjs/ecma402-abstract": "2.3.4", "@formatjs/fast-memoize": "2.2.7", "@formatjs/icu-messageformat-parser": "2.11.2", "tslib": "^2.8.0" } }, "sha512-UmdmHUmp5CIKKjSoE10la5yfU+AYJAaiYLsodbjL4lji83JNvgOQUjGaGhGrpFCb0Uh7sl7qfP1IyILa8Z40ug=="], + + "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], + + "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], + + "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], + + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], + + "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], + + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + + "is-promise": ["is-promise@2.2.2", "", {}, "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ=="], + + "is-reference": ["is-reference@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.6" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="], + + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], + + "jiti": ["jiti@1.21.7", "", { "bin": { "jiti": "bin/jiti.js" } }, "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A=="], + + "js-tiktoken": ["js-tiktoken@1.0.21", "", { "dependencies": { "base64-js": "^1.5.1" } }, "sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g=="], + + "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + + "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], + + "langsmith": ["langsmith@0.3.87", "", { "dependencies": { "@types/uuid": "^10.0.0", "chalk": "^4.1.2", "console-table-printer": "^2.12.1", "p-queue": "^6.6.2", "semver": "^7.6.3", "uuid": "^10.0.0" }, "peerDependencies": { "@opentelemetry/api": "*", "@opentelemetry/exporter-trace-otlp-proto": "*", "@opentelemetry/sdk-trace-base": "*", "openai": "*" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/exporter-trace-otlp-proto", "@opentelemetry/sdk-trace-base", "openai"] }, "sha512-XXR1+9INH8YX96FKWc5tie0QixWz6tOqAsAKfcJyPkE0xPep+NDz0IQLR32q4bn10QK3LqD2HN6T3n6z1YLW7Q=="], + + "lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="], + + "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], + + "locate-character": ["locate-character@3.0.0", "", {}, "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="], + + "lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + + "lru-queue": ["lru-queue@0.1.0", "", { "dependencies": { "es5-ext": "~0.10.2" } }, "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ=="], + + "lz-string": ["lz-string@1.5.0", "", { "bin": { "lz-string": "bin/bin.js" } }, "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ=="], + + "magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="], + + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + + "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], + + "memoizee": ["memoizee@0.4.17", "", { "dependencies": { "d": "^1.0.2", "es5-ext": "^0.10.64", "es6-weak-map": "^2.0.3", "event-emitter": "^0.3.5", "is-promise": "^2.2.2", "lru-queue": "^0.1.0", "next-tick": "^1.1.0", "timers-ext": "^0.1.7" } }, "sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA=="], + + "merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], + + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], + + "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + + "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], + + "mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], + + "minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + + "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], + + "moment": ["moment@2.29.4", "", {}, "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w=="], + + "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "mustache": ["mustache@4.2.0", "", { "bin": { "mustache": "bin/mustache" } }, "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ=="], + + "mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="], + + "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + + "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], + + "next-tick": ["next-tick@1.1.0", "", {}, "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="], + + "node-releases": ["node-releases@2.0.19", "", {}, "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="], + + "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], + + "normalize-range": ["normalize-range@0.1.2", "", {}, "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA=="], + + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], + + "object-hash": ["object-hash@3.0.0", "", {}, "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw=="], + + "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], + + "obsidian": ["obsidian@1.10.0", "", { "dependencies": { "@types/codemirror": "5.60.8", "moment": "2.29.4" }, "peerDependencies": { "@codemirror/state": "6.5.0", "@codemirror/view": "6.38.1" } }, "sha512-F7hhnmGRQD1TanDPFT//LD3iKNUVd7N8sKL7flCCHRszfTxpDJ39j3T7LHbcGpyid906i6lD5oO+cnfLBzJMKw=="], + + "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], + + "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], + + "p-finally": ["p-finally@1.0.0", "", {}, "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow=="], + + "p-queue": ["p-queue@6.6.2", "", { "dependencies": { "eventemitter3": "^4.0.4", "p-timeout": "^3.2.0" } }, "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ=="], + + "p-retry": ["p-retry@4.6.2", "", { "dependencies": { "@types/retry": "0.12.0", "retry": "^0.13.1" } }, "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ=="], + + "p-timeout": ["p-timeout@3.2.0", "", { "dependencies": { "p-finally": "^1.0.0" } }, "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg=="], + + "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], + + "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], + + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], + + "path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + + "path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + + "pify": ["pify@2.3.0", "", {}, "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="], + + "pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], + + "pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="], + + "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], + + "postcss-import": ["postcss-import@15.1.0", "", { "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", "resolve": "^1.1.7" }, "peerDependencies": { "postcss": "^8.0.0" } }, "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew=="], + + "postcss-js": ["postcss-js@4.0.1", "", { "dependencies": { "camelcase-css": "^2.0.1" }, "peerDependencies": { "postcss": "^8.4.21" } }, "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw=="], + + "postcss-load-config": ["postcss-load-config@4.0.2", "", { "dependencies": { "lilconfig": "^3.0.0", "yaml": "^2.3.4" }, "peerDependencies": { "postcss": ">=8.0.9", "ts-node": ">=9.0.0" }, "optionalPeers": ["postcss", "ts-node"] }, "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ=="], + + "postcss-nested": ["postcss-nested@6.2.0", "", { "dependencies": { "postcss-selector-parser": "^6.1.1" }, "peerDependencies": { "postcss": "^8.2.14" } }, "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ=="], + + "postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="], + + "postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="], + + "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], + + "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + + "qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="], + + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], + + "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], + + "raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="], + + "read-cache": ["read-cache@1.0.0", "", { "dependencies": { "pify": "^2.3.0" } }, "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA=="], + + "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], + + "resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="], + + "retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="], + + "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], + + "rollup": ["rollup@4.53.3", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.53.3", "@rollup/rollup-android-arm64": "4.53.3", "@rollup/rollup-darwin-arm64": "4.53.3", "@rollup/rollup-darwin-x64": "4.53.3", "@rollup/rollup-freebsd-arm64": "4.53.3", "@rollup/rollup-freebsd-x64": "4.53.3", "@rollup/rollup-linux-arm-gnueabihf": "4.53.3", "@rollup/rollup-linux-arm-musleabihf": "4.53.3", "@rollup/rollup-linux-arm64-gnu": "4.53.3", "@rollup/rollup-linux-arm64-musl": "4.53.3", "@rollup/rollup-linux-loong64-gnu": "4.53.3", "@rollup/rollup-linux-ppc64-gnu": "4.53.3", "@rollup/rollup-linux-riscv64-gnu": "4.53.3", "@rollup/rollup-linux-riscv64-musl": "4.53.3", "@rollup/rollup-linux-s390x-gnu": "4.53.3", "@rollup/rollup-linux-x64-gnu": "4.53.3", "@rollup/rollup-linux-x64-musl": "4.53.3", "@rollup/rollup-openharmony-arm64": "4.53.3", "@rollup/rollup-win32-arm64-msvc": "4.53.3", "@rollup/rollup-win32-ia32-msvc": "4.53.3", "@rollup/rollup-win32-x64-gnu": "4.53.3", "@rollup/rollup-win32-x64-msvc": "4.53.3", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA=="], + + "router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="], + + "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], + + "runed": ["runed@0.35.1", "", { "dependencies": { "dequal": "^2.0.3", "esm-env": "^1.0.0", "lz-string": "^1.5.0" }, "peerDependencies": { "@sveltejs/kit": "^2.21.0", "svelte": "^5.7.0" }, "optionalPeers": ["@sveltejs/kit"] }, "sha512-2F4Q/FZzbeJTFdIS/PuOoPRSm92sA2LhzTnv6FXhCoENb3huf5+fDuNOg1LNvGOouy3u/225qxmuJvcV3IZK5Q=="], + + "sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="], + + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + + "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + + "send": ["send@1.2.1", "", { "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="], + + "serve-static": ["serve-static@2.2.1", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw=="], + + "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], + + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "side-channel": ["side-channel@1.1.0", "", { "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" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], + + "side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="], + + "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="], + + "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "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" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], + + "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + + "simple-wcswidth": ["simple-wcswidth@1.1.2", "", {}, "sha512-j7piyCjAeTDSjzTSQ7DokZtMNwNlEAyxqSZeCS+CXH7fJ4jx3FuJ/mTW3mE+6JLs4VJBbcll0Kjn+KXI5t21Iw=="], + + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + + "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], + + "string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + + "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="], + + "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "style-mod": ["style-mod@4.1.2", "", {}, "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw=="], + + "style-to-object": ["style-to-object@1.0.9", "", { "dependencies": { "inline-style-parser": "0.2.4" } }, "sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw=="], + + "sucrase": ["sucrase@3.35.0", "", { "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", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA=="], + + "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + + "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], + + "svelte": ["svelte@5.41.0", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "acorn": "^8.12.1", "aria-query": "^5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "esm-env": "^1.2.1", "esrap": "^2.1.0", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-mP3vFFv5OUM5JN189+nJVW74kQ1dGqUrXTEzvCEVZqessY0GxZDls1nWVvt4Sxyv2USfQvAZO68VRaeIZvpzKg=="], + + "svelte-check": ["svelte-check@4.3.3", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "chokidar": "^4.0.1", "fdir": "^6.2.0", "picocolors": "^1.0.0", "sade": "^1.7.4" }, "peerDependencies": { "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": ">=5.0.0" }, "bin": { "svelte-check": "bin/svelte-check" } }, "sha512-RYP0bEwenDXzfv0P1sKAwjZSlaRyqBn0Fz1TVni58lqyEiqgwztTpmodJrGzP6ZT2aHl4MbTvWP6gbmQ3FOnBg=="], + + "svelte-i18n": ["svelte-i18n@4.0.1", "", { "dependencies": { "cli-color": "^2.0.3", "deepmerge": "^4.2.2", "esbuild": "^0.19.2", "estree-walker": "^2", "intl-messageformat": "^10.5.3", "sade": "^1.8.1", "tiny-glob": "^0.2.9" }, "peerDependencies": { "svelte": "^3 || ^4 || ^5" }, "bin": { "svelte-i18n": "dist/cli.js" } }, "sha512-jaykGlGT5PUaaq04JWbJREvivlCnALtT+m87Kbm0fxyYHynkQaxQMnIKHLm2WeIuBRoljzwgyvz0Z6/CMwfdmQ=="], + + "svelte-toolbelt": ["svelte-toolbelt@0.10.6", "", { "dependencies": { "clsx": "^2.1.1", "runed": "^0.35.1", "style-to-object": "^1.0.8" }, "peerDependencies": { "svelte": "^5.30.2" } }, "sha512-YWuX+RE+CnWYx09yseAe4ZVMM7e7GRFZM6OYWpBKOb++s+SQ8RBIMMe+Bs/CznBMc0QPLjr+vDBxTAkozXsFXQ=="], + + "tabbable": ["tabbable@6.2.0", "", {}, "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="], + + "tailwindcss": ["tailwindcss@3.4.18", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.6.0", "didyoumean": "^1.2.2", "dlv": "^1.1.3", "fast-glob": "^3.3.2", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.21.7", "lilconfig": "^3.1.3", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.1.1", "postcss": "^8.4.47", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", "postcss-nested": "^6.2.0", "postcss-selector-parser": "^6.1.2", "resolve": "^1.22.8", "sucrase": "^3.35.0" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" } }, "sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ=="], + + "thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="], + + "thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="], + + "timers-ext": ["timers-ext@0.1.8", "", { "dependencies": { "es5-ext": "^0.10.64", "next-tick": "^1.1.0" } }, "sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww=="], + + "tiny-glob": ["tiny-glob@0.2.9", "", { "dependencies": { "globalyzer": "0.1.0", "globrex": "^0.1.2" } }, "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg=="], + + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], + + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + + "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], + + "ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "type": ["type@2.7.3", "", {}, "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ=="], + + "type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="], + + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + + "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], + + "update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="], + + "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + + "uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="], + + "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], + + "vite": ["vite@7.2.7", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-ITcnkFeR3+fI8P1wMgItjGrR10170d8auB4EpMLPqmx6uxElH3a/hHGQabSHKdqd4FXWO1nFIp9rRn7JQ34ACQ=="], + + "vitefu": ["vitefu@1.0.6", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" }, "optionalPeers": ["vite"] }, "sha512-+Rex1GlappUyNN6UfwbVZne/9cYC4+R2XDk9xkNXBKMw6HQagdX9PgZ8V2v1WUSK1wfBLp7qbI1+XSNIlB1xmA=="], + + "w3c-keyname": ["w3c-keyname@2.2.8", "", {}, "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="], + + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], + + "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], + + "yaml": ["yaml@2.8.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ=="], + + "zimmerframe": ["zimmerframe@1.1.2", "", {}, "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w=="], + + "zod": ["zod@4.2.1", "", {}, "sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw=="], + + "zod-to-json-schema": ["zod-to-json-schema@3.25.0", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ=="], + + "@langchain/core/uuid": ["uuid@10.0.0", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ=="], + + "@langchain/langgraph/uuid": ["uuid@10.0.0", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ=="], + + "@langchain/langgraph-checkpoint/uuid": ["uuid@10.0.0", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ=="], + + "@langchain/langgraph-sdk/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="], + + "@modelcontextprotocol/sdk/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@sveltejs/vite-plugin-svelte/debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="], + + "@sveltejs/vite-plugin-svelte-inspector/debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="], + + "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "langsmith/uuid": ["uuid@10.0.0", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ=="], + + "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "router/is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="], + + "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "svelte-i18n/esbuild": ["esbuild@0.19.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.19.12", "@esbuild/android-arm": "0.19.12", "@esbuild/android-arm64": "0.19.12", "@esbuild/android-x64": "0.19.12", "@esbuild/darwin-arm64": "0.19.12", "@esbuild/darwin-x64": "0.19.12", "@esbuild/freebsd-arm64": "0.19.12", "@esbuild/freebsd-x64": "0.19.12", "@esbuild/linux-arm": "0.19.12", "@esbuild/linux-arm64": "0.19.12", "@esbuild/linux-ia32": "0.19.12", "@esbuild/linux-loong64": "0.19.12", "@esbuild/linux-mips64el": "0.19.12", "@esbuild/linux-ppc64": "0.19.12", "@esbuild/linux-riscv64": "0.19.12", "@esbuild/linux-s390x": "0.19.12", "@esbuild/linux-x64": "0.19.12", "@esbuild/netbsd-x64": "0.19.12", "@esbuild/openbsd-x64": "0.19.12", "@esbuild/sunos-x64": "0.19.12", "@esbuild/win32-arm64": "0.19.12", "@esbuild/win32-ia32": "0.19.12", "@esbuild/win32-x64": "0.19.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg=="], + + "tailwindcss/chokidar": ["chokidar@3.6.0", "", { "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" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], + + "tinyglobby/fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + + "vite/fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + + "wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="], + + "wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "svelte-i18n/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.19.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA=="], + + "svelte-i18n/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.19.12", "", { "os": "android", "cpu": "arm" }, "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w=="], + + "svelte-i18n/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.19.12", "", { "os": "android", "cpu": "arm64" }, "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA=="], + + "svelte-i18n/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.19.12", "", { "os": "android", "cpu": "x64" }, "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew=="], + + "svelte-i18n/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.19.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g=="], + + "svelte-i18n/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.19.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A=="], + + "svelte-i18n/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.19.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA=="], + + "svelte-i18n/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.19.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg=="], + + "svelte-i18n/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.19.12", "", { "os": "linux", "cpu": "arm" }, "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w=="], + + "svelte-i18n/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.19.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA=="], + + "svelte-i18n/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.19.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA=="], + + "svelte-i18n/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA=="], + + "svelte-i18n/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w=="], + + "svelte-i18n/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.19.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg=="], + + "svelte-i18n/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg=="], + + "svelte-i18n/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.19.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg=="], + + "svelte-i18n/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.19.12", "", { "os": "linux", "cpu": "x64" }, "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg=="], + + "svelte-i18n/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.19.12", "", { "os": "none", "cpu": "x64" }, "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA=="], + + "svelte-i18n/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.19.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw=="], + + "svelte-i18n/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.19.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA=="], + + "svelte-i18n/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.19.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A=="], + + "svelte-i18n/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.19.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ=="], + + "svelte-i18n/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.19.12", "", { "os": "win32", "cpu": "x64" }, "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA=="], + + "tailwindcss/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "tailwindcss/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], + + "wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "tailwindcss/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + } +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 00000000..9f53a776 --- /dev/null +++ b/flake.lock @@ -0,0 +1,25 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1765186076, + "narHash": "sha256-hM20uyap1a0M9d344I692r+ik4gTMyj60cQWO+hAYP8=", + "rev": "addf7cf5f383a3101ecfba091b98d0a1263dc9b8", + "revCount": 908783, + "type": "tarball", + "url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.1.908783%2Brev-addf7cf5f383a3101ecfba091b98d0a1263dc9b8/019b03a0-b1e4-7f2a-9d10-ad8434116660/source.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://flakehub.com/f/NixOS/nixpkgs/0.1" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 00000000..c260345e --- /dev/null +++ b/flake.nix @@ -0,0 +1,35 @@ +{ + description = "A Nix-flake-based Bun development environment"; + + inputs.nixpkgs.url = "https://flakehub.com/f/NixOS/nixpkgs/0.1"; # unstable Nixpkgs + + outputs = + { self, ... }@inputs: + + let + supportedSystems = [ + "x86_64-linux" + "aarch64-linux" + "x86_64-darwin" + "aarch64-darwin" + ]; + forEachSupportedSystem = + f: + inputs.nixpkgs.lib.genAttrs supportedSystems ( + system: + f { + pkgs = import inputs.nixpkgs { inherit system; }; + } + ); + in + { + devShells = forEachSupportedSystem ( + { pkgs }: + { + default = pkgs.mkShellNoCC { + packages = with pkgs; [ bun ]; + }; + } + ); + }; +} diff --git a/manifest.json b/manifest.json index f17a6fde..9432daca 100644 --- a/manifest.json +++ b/manifest.json @@ -1,10 +1,10 @@ { - "id": "smart-second-brain", - "name": "Smart Second Brain", - "description": "Interact with your privacy focused assistant, leveraging Ollama or OpenAI, making your second brain even smarter.", - "author": "Leo310, nicobrauchtgit", - "authorUrl": "https://github.com/nicobrauchtgit", - "version": "1.3.0", - "minAppVersion": "1.5.0", - "isDesktopOnly": true + "id": "smart-second-brain", + "name": "Smart Second Brain", + "description": "Interact with your privacy focused assistant, leveraging Ollama or OpenAI, making your second brain even smarter.", + "author": "Leo310, nicobrauchtgit", + "authorUrl": "https://github.com/nicobrauchtgit", + "version": "1.3.0", + "minAppVersion": "1.5.0", + "isDesktopOnly": true } diff --git a/package.json b/package.json index cc918144..7deb65a2 100644 --- a/package.json +++ b/package.json @@ -1,41 +1,42 @@ { - "name": "smart-second-brain", - "version": "1.1.0", - "main": "main.js", - "devDependencies": { - "@biomejs/biome": "1.2.2", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-typescript": "^11.1.6", - "@sveltejs/vite-plugin-svelte": "^2.4.6", - "@tsconfig/svelte": "^4.0.1", - "@typescript-eslint/eslint-plugin": "^6.19.0", - "@typescript-eslint/parser": "^6.19.0", - "autoprefixer": "^10.4.16", - "builtin-modules": "^3.3.0", - "bun-types": "latest", - "eslint": "^8.56.0", - "obsidian": "^1.4.11", - "postcss": "^8.4.30", - "svelte": "^4.2.1", - "svelte-check": "^3.5.2", - "tailwindcss": "^3.3.3", - "tslib": "^2.6.2", - "typescript": "^5.2.2", - "vite": "^4.4.9" - }, - "private": true, - "scripts": { - "dev": "vite build --mode development --watch", - "build": "vite build --mode production", - "check": "svelte-check --tsconfig ./tsconfig.json", - "format": "biome format --write ./src", - "lint": "biome lint --apply-unsafe ./src" - }, - "type": "module", - "dependencies": { - "i18next": "^23.8.2", - "monkey-around": "^2.3.0", - "nanoid": "^5.0.4", - "svelte-i18n": "^4.0.0" - } + "name": "smart-second-brain", + "version": "0.1.0", + "main": "main.js", + "devDependencies": { + "@biomejs/biome": "^1.9.4", + "@langchain/langgraph-checkpoint": "^1.0.0", + "@langchain/mcp-adapters": "^1.0.2", + "@langchain/tavily": "^1.0.1", + "@sveltejs/vite-plugin-svelte": "^5.1.1", + "@tsconfig/svelte": "^5.0.5", + "autoprefixer": "^10.4.21", + "obsidian": "^1.10.0", + "postcss": "^8.5.6", + "svelte": "^5.41.0", + "svelte-check": "^4.3.3", + "tailwindcss": "^3.4.18", + "tslib": "^2.8.1", + "typescript": "^5.9.3", + "vite": "^7.0.0" + }, + "private": true, + "scripts": { + "dev": "vite build --mode development --watch", + "build": "vite build --mode production", + "check": "svelte-check --tsconfig ./tsconfig.json", + "format": "biome format --write ./src", + "lint": "biome lint --apply-unsafe ./src" + }, + "type": "module", + "dependencies": { + "@selemondev/svgl-svelte": "^0.0.3", + "@tanstack/svelte-query": "^6.0.10", + "bits-ui": "^2.11.8", + "builtin-modules": "^5.0.0", + "dexie": "^4.2.1", + "i18next": "^23.16.8", + "svelte-i18n": "^4.0.1", + "uuid": "^11.1.0", + "zod": "^4.2.1" + } } diff --git a/src/SmartSecondBrain.ts b/src/SmartSecondBrain.ts deleted file mode 100644 index 862c8bb8..00000000 --- a/src/SmartSecondBrain.ts +++ /dev/null @@ -1,232 +0,0 @@ -import { App, Notice, TFile, normalizePath } from 'obsidian'; -import { Papa, obsidianDocumentLoader, type GenModel } from 'papa-ts'; -import { get } from 'svelte/store'; -import { wildTest } from './components/Settings/FuzzyModal'; -import { isOllamaRunning, getOllamaModels } from './controller/Ollama'; -import { isAPIKeyValid } from './controller/OpenAI'; -import Log, { LogLvl } from './logging'; -import { data, papaState, errorState, papaIndexingProgress, chatHistory, serializeChatHistory, runState, runContent, papaIndexingTimeLeft } from './store'; -import { _ } from 'svelte-i18n'; - -export default class SmartSecondBrain { - private papa: Papa; - private app: App; - private needsToSaveVectorStoreData = false; - private pluginDir: string; - - constructor(app: App, pluginDir: string) { - this.app = app; - this.pluginDir = pluginDir; - } - - async init() { - const d = get(data); - const t = get(_); - if (get(papaState) === 'running') return new Notice(t('notice.still_running'), 4000); - else if (get(papaState) === 'indexing' || get(papaState) === 'loading') { - return new Notice(t('notice.still_indexing'), 4000); - } else if (d.isIncognitoMode && !(await isOllamaRunning())) { - papaState.set('error'); - errorState.set('ollama-not-running'); - return new Notice(t('notice.ollama_not_running'), 4000); - } else if (d.isIncognitoMode) { - const models = await getOllamaModels(); - if (!models.includes(d.ollamaGenModel.model)) { - papaState.set('error'); - errorState.set('ollama-gen-model-not-installed'); - return new Notice(t('notice.ollama_gen_model'), 4000); - } - if (!models.includes(d.ollamaEmbedModel.model)) { - papaState.set('error'); - errorState.set('ollama-embed-model-not-installed'); - return new Notice(t('notice.ollama_embed_model'), 4000); - } - } else if (!d.isIncognitoMode && !(await isAPIKeyValid(d.openAIGenModel.openAIApiKey))) { - papaState.set('error'); - return new Notice(t('notice.openai_key'), 4000); - } - if (get(papaState) !== 'indexing-pause') { - papaState.set('loading'); - Log.info( - 'Initializing second brain', - '\nGen Model: ', - d.isIncognitoMode ? d.ollamaGenModel : d.openAIGenModel, - '\nEmbed Model: ', - d.isIncognitoMode ? d.ollamaEmbedModel : d.openAIEmbedModel - ); - try { - this.papa = new Papa(); - await this.papa.init({ - genModel: d.isIncognitoMode ? d.ollamaGenModel : d.openAIGenModel, - embedModel: d.isIncognitoMode ? d.ollamaEmbedModel : d.openAIEmbedModel, - langsmithApiKey: d.debugginLangchainKey || undefined, - logLvl: d.isVerbose ? LogLvl.DEBUG : LogLvl.DISABLED, - }); - } catch (e) { - Log.error(e); - papaState.set('error'); - return new Notice(t('notice.failed', { values: { error: e } }), 4000); - } - // check if vector store data exists - if (await this.app.vault.adapter.exists(this.getVectorStoreFile())) { - const vectorStoreData = await this.app.vault.adapter.readBinary(this.getVectorStoreFile()); - await this.papa.load(vectorStoreData); - } - } - const mdFiles = this.app.vault.getMarkdownFiles(); - const docs = await obsidianDocumentLoader( - this.app, - mdFiles.filter((mdFile: TFile) => { - for (const exclude of d.excludeFF) if (wildTest(exclude, mdFile.path)) return false; - return true; - }) - ); - papaState.set('indexing'); - let needsSave = false; - try { - let lastTime = Date.now(); - const timePerDoc = []; - - let lastTotalDocs = 0; - for await (const result of this.papa.embedDocuments(docs)) { - needsSave = (!this.needsToSaveVectorStoreData && result.numAdded > 0) || result.numDeleted > 0; - const progress = ((result.numAdded + result.numSkipped) / docs.length) * 100; - papaIndexingProgress.set(Math.max(progress, get(papaIndexingProgress))); - const currentTime = Date.now(); - timePerDoc.push(currentTime - lastTime); - const numberOfDocumentsRemaining = docs.length * (1 - get(papaIndexingProgress) / 100); - const averageTimePerDocumentInSeconds = - timePerDoc.reduce((a, b) => a + b, 0) / timePerDoc.length / (result.numAdded + result.numSkipped - lastTotalDocs) / 1000; - lastTotalDocs = result.numAdded + result.numSkipped; - if (timePerDoc.length > 5) { - timePerDoc.shift(); - papaIndexingTimeLeft.set(Math.ceil(averageTimePerDocumentInSeconds * numberOfDocumentsRemaining)); - } - lastTime = currentTime; - if (get(papaState) === 'indexing-pause') break; - } - } catch (e) { - Log.error(e); - papaState.set('error'); - errorState.set('failed-indexing'); - new Notice(t('notice.failed_indexing'), 4000); - } - - this.needsToSaveVectorStoreData = needsSave; - this.saveVectorStoreData(); - if (get(papaIndexingProgress) === 100) { - new Notice(t('notice.done'), 2000); - papaIndexingProgress.set(0); - papaState.set('idle'); - } - } - - async cancelIndexing() { - // if (this.app.vault.adapter.exists(this.getVectorStoreFile())) await this.app.vault.adapter.remove(this.getVectorStoreFile()); - papaState.set('uninitialized'); - papaIndexingProgress.set(0); - } - - canRunPapa() { - const t = get(_); - if (get(papaState) === 'running') return new Notice(t('notice.still_running'), 4000) && false; - else if (get(papaState) === 'indexing' || get(papaState) === 'indexing-pause' || get(papaState) === 'loading') - return new Notice(t('notice.still_indexing'), 4000) && false; - else if (get(papaState) === 'error') return new Notice(t('notice.error'), 4000) && false; - else if (get(papaState) !== 'idle') return new Notice(t('notice.not_initialized'), 4000) && false; - return true; - } - - async runPapa() { - papaState.set('running'); - try { - const cH = get(chatHistory); - const userQuery = cH[cH.length - 1].content; - const responseStream = this.papa.run({ - isRAG: get(data).isUsingRag, - userQuery, - chatHistory: serializeChatHistory(cH.slice(0, cH.length - 1)), - lang: get(data).assistantLanguage, - }); - for await (const response of responseStream) { - runState.set(response.status); - runContent.set(response.content); - } - } catch (error) { - const errorMsg = get(_)('notice.run_failed', { values: { error } }); - // Log.error(errorMsg); - runContent.set(errorMsg); - // papaState.set('error'); - // errorState.set('run-failed'); - new Notice(errorMsg, 4000); - } - papaState.set('idle'); - } - - async createFilenameForChat() { - let fileName = await this.papa.createTitleFromChatHistory(get(data).assistantLanguage, serializeChatHistory(get(chatHistory))); - // File name cannot contain any of the following characters: \, /, :, *, ?, ", <, >, |, # - fileName = fileName.replace(/[\\/:*?"<>|#]/g, ''); - return fileName; - } - - getVectorStoreFile() { - const d = get(data); - return normalizePath(this.pluginDir + '/vectorstores/' + (d.isIncognitoMode ? d.ollamaEmbedModel.model : d.openAIEmbedModel.model) + '.bin'); - } - - async saveVectorStoreData() { - if (this.needsToSaveVectorStoreData && this.papa) { - Log.debug('Saving vector store data'); - this.needsToSaveVectorStoreData = false; - // create vectorstores directory if it doesn't exist - (await this.app.vault.adapter.exists(this.pluginDir + '/vectorstores')) || (await this.app.vault.adapter.mkdir(this.pluginDir + '/vectorstores')); - await this.app.vault.adapter.writeBinary(this.getVectorStoreFile(), await this.papa.getData()); - Log.info('Saved vector store data'); - } - } - - async onFileChange(file: TFile) { - if (!this.papa) return; - for (const exclude of get(data).excludeFF) if (wildTest(exclude, file.path)) return; - const docs = await obsidianDocumentLoader(this.app, [file]); - this.papa.embedDocuments(docs, 'byFile'); - this.needsToSaveVectorStoreData = true; - } - async onFileDelete(file: TFile) { - if (!this.papa) return; - for (const exclude of get(data).excludeFF) if (wildTest(exclude, file.path)) return; - const docs = await obsidianDocumentLoader(this.app, [file]); - this.papa.deleteDocuments({ docs }); - this.needsToSaveVectorStoreData = true; - } - async onFileRename(file: TFile, oldPath: string) { - if (!this.papa) return; - for (const exclude of get(data).excludeFF) if (wildTest(exclude, file.path)) return; - await this.papa.deleteDocuments({ sources: [oldPath] }); - const docs = await obsidianDocumentLoader(this.app, [file]); - this.papa.embedDocuments(docs, 'byFile'); - this.needsToSaveVectorStoreData = true; - } - - setSimilarityThreshold(value: number) { - if (this.papa) this.papa.setSimilarityThreshold(value); - } - - stopRun() { - if (this.papa) this.papa.stopRun(); - papaState.set('idle'); - } - - setNumOfDocsToRetrieve(k: number) { - if (this.papa) this.papa.setNumOfDocsToRetrieve(k); - } - - setGenModel(genModel: GenModel) { - if (this.papa) this.papa.setGenModel(genModel); - } - - setTracer(langchainKey: string) { - if (this.papa) this.papa.setTracer(langchainKey); - } -} diff --git a/src/agent/AgentManager.ts b/src/agent/AgentManager.ts new file mode 100644 index 00000000..652b544e --- /dev/null +++ b/src/agent/AgentManager.ts @@ -0,0 +1,508 @@ +import { + Agent, + ProviderRegistry, + type ThreadSnapshot, + LangSmithTelemetry, + type Telemetry, + type BuiltInProviderOptions, + ProviderAuthError, + ProviderEndpointError, + ProviderRegistryError, + type ThreadMessage, + type ChooseModelParams, + type ThreadHistory, +} from "papa-ts"; +import { normalizePath } from "obsidian"; +import { ObsidianChatManager } from "./ObsidianChatManager"; +import { createSearchNotesTool } from "../tools/searchNotes"; +import { createGetAllTagsTool } from "../tools/getAllTags"; +import { createExecuteDataviewTool } from "../tools/executeDataview"; +import { createGetPropertiesTool } from "../tools/getProperties"; +import { createReadNoteTool } from "../tools/readNote"; +import { createSystemPrompt } from "./prompts"; +import { createObsidianFetch } from "../utils/obsidianFetch"; +import { getData } from "../stores/dataStore.svelte"; +import type { RegisteredProvider } from "../types/providers"; +import type SecondBrainPlugin from "../main"; +import type { ChatModel } from "../stores/chatStore.svelte"; +import { createThreadId } from "../utils/threadId"; + +export type ValidationResult = + | { success: true } + | { success: false; message: string }; + +declare const MultiServerMCPClient: any; + +/** + * Maps the UI ChatModel type to papa-ts ChooseModelParams. + */ +function toChooseModelParams(model: ChatModel): ChooseModelParams { + return { + provider: model.provider, + chatModel: model.model, + options: model.modelConfig, + }; +} + +export class AgentManager { + private plugin: SecondBrainPlugin; + private agent: Agent | null = null; + private chatManager: ObsidianChatManager; + private registry: ProviderRegistry; + + constructor(plugin: SecondBrainPlugin) { + this.plugin = plugin; + this.chatManager = new ObsidianChatManager(plugin); + this.registry = new ProviderRegistry(); + } + + /** + * Configures a specific provider on the given registry. + */ + private async configureProviderOnRegistry( + registry: ProviderRegistry, + provider: RegisteredProvider, + options: BuiltInProviderOptions, + ): Promise { + switch (provider) { + case "OpenAI": + await registry.useOpenAI(options); + break; + case "CustomOpenAI": + await registry.useOpenAI(options); + break; + case "Anthropic": + await registry.useAnthropic(options); + break; + case "Ollama": + await registry.useOllama(options); + break; + default: + throw new Error(`Unsupported provider: ${provider}`); + } + } + + /** + * Configures a provider on the main registry. + */ + private async configureRegistry( + provider: RegisteredProvider, + options: BuiltInProviderOptions, + ): Promise { + await this.configureProviderOnRegistry(this.registry, provider, options); + } + + /** + * Tests and configures a provider on the actual registry. + * Returns a ValidationResult indicating success or failure with a message. + */ + async testProviderConfig( + provider: RegisteredProvider, + options: BuiltInProviderOptions, + ): Promise { + try { + await this.configureProviderOnRegistry(this.registry, provider, options); + return { success: true }; + } catch (error) { + if (error instanceof ProviderAuthError) { + return { success: false, message: "Invalid API key" }; + } + if (error instanceof ProviderEndpointError) { + return { + success: false, + message: "Invalid base URL or endpoint unreachable", + }; + } + if (error instanceof ProviderRegistryError) { + return { success: false, message: error.message }; + } + return { + success: false, + message: "Provider configuration failed", + }; + } + } + + private configureTelemetry(): Telemetry | undefined { + const data = getData(); + if (data.enableLangSmith && data.langSmithApiKey) { + try { + const telemetry = new LangSmithTelemetry({ + projectName: data.langSmithProject || "obsidian-agent", + apiKey: data.langSmithApiKey, + endpoint: data.langSmithEndpoint || "https://api.smith.langchain.com", + flushOnComplete: true, + }); + console.log("Smart Second Brain: LangSmith telemetry enabled"); + return telemetry; + } catch (e) { + console.error( + "Smart Second Brain: Failed to initialize LangSmith telemetry", + e, + ); + } + } + return undefined; + } + + private async bindTools(agent: Agent) { + const searchNotesTool = createSearchNotesTool(this.plugin.app); + const getAllTagsTool = createGetAllTagsTool(this.plugin.app); + const executeDataviewTool = createExecuteDataviewTool(this.plugin.app); + const getPropertiesTool = createGetPropertiesTool(this.plugin.app); + const readNoteTool = createReadNoteTool(this.plugin.app); + + const tools: any[] = [ + searchNotesTool, + getAllTagsTool, + executeDataviewTool, + getPropertiesTool, + readNoteTool, + ]; + + // Load MCP tools if configured (use getData()) + const data = getData(); + if (data.mcpServers && Object.keys(data.mcpServers).length > 0) { + try { + console.log( + "Smart Second Brain: Initializing MCP client...", + data.mcpServers, + ); + + // HACK: Monkey patch the global fetch for the entire lifecycle + if (!(window as any)._originalFetch) { + (window as any)._originalFetch = window.fetch; + window.fetch = createObsidianFetch( + (window as any)._originalFetch, + ) as any; + } + + try { + const mcpClient = new MultiServerMCPClient(data.mcpServers); + const mcpTools = await mcpClient.getTools(); + console.log( + `Smart Second Brain: Loaded ${mcpTools.length} MCP tools`, + ); + tools.push(...mcpTools); + } catch (e) { + console.error("Failed to get MCP tools", e); + } + } catch (error) { + console.error("Smart Second Brain: Failed to load MCP tools", error); + } + } + + agent.bindTools(tools); + } + + private async ensureAgent(): Promise { + if (!this.agent) { + await this.initialize(); + } + + if (!this.agent) { + throw new Error("Agent initialization failed."); + } + return this.agent; + } + + async initialize(): Promise { + // Load chats + await this.chatManager.load(); + + // Cleanup existing agent if any + this.agent = null; + + // Reset registry for fresh configuration + this.registry = new ProviderRegistry(); + + const pluginData = getData(); + + // Configure all providers - use for...of to properly await each + const configuredProviders = pluginData.getConfiguredProviders(); + for (const provider of configuredProviders) { + const options = pluginData.getProviderAuthParams(provider); + await this.configureRegistry(provider, options); + } + + console.log(this.registry); + + // Configure Telemetry (use getData()) + const telemetry = this.configureTelemetry(); + + // Create agent with checkpoint storage + // The chatManager acts as both checkpointer and thread store + this.agent = new Agent({ + registry: this.registry, + checkpointer: this.chatManager, + threadStore: this.chatManager.asThreadStore(), + telemetry, + }); + + // Check for available plugins to adjust prompt capabilities + // @ts-ignore - Dynamic access to plugins + const hasChartsPlugin = + this.plugin.app.plugins?.enabledPlugins?.has("obsidian-charts"); + + // Set prompt + this.agent.setPrompt(createSystemPrompt(hasChartsPlugin)); + + const defaultModel = pluginData.getDefaultChatModel(); + if (defaultModel) { + await this.agent.chooseModel(toChooseModelParams(defaultModel)); + } + + // Bind tools + await this.bindTools(this.agent); + } + + async *streamQuery( + query: string, + threadId: string = "default-thread", + signal?: AbortSignal, + ): AsyncGenerator< + | { type: "token"; token: string } + | { + type: "tool_start"; + toolCallId: string; + toolName: string; + input: unknown; + } + | { + type: "tool_end"; + toolCallId: string; + toolName: string; + output: unknown; + } + | { type: "result"; result: any }, + void, + unknown + > { + const agent = await this.ensureAgent(); + + const defaultModel = getData().getDefaultChatModel(); + if (defaultModel) { + await agent.chooseModel(toChooseModelParams(defaultModel)); + } else { + throw new Error("No chat model configured"); + } + + try { + for await (const chunk of agent.streamTokens({ + query, + threadId, + signal, + })) { + // Check if aborted before yielding + if (signal?.aborted) { + break; + } + switch (chunk.type) { + case "token": + yield { type: "token", token: chunk.token }; + break; + case "tool_start": + yield { + type: "tool_start", + toolCallId: chunk.toolCallId, + toolName: chunk.toolName, + input: chunk.input, + }; + break; + case "tool_end": + yield { + type: "tool_end", + toolCallId: chunk.toolCallId, + toolName: chunk.toolName, + output: chunk.output, + }; + break; + case "result": + yield { type: "result", result: chunk.result }; + break; + default: + break; + } + } + } catch (error) { + // Don't log abort errors as they're expected during cancellation + if (error instanceof Error && error.name === "AbortError") { + return; + } + console.error("Smart Second Brain: Error streaming query", error); + throw error; + } finally { + // Cleanup logging - stream completed or aborted + if (signal?.aborted) { + console.log("Smart Second Brain: Stream aborted by user"); + } + } + } + + async getAvailableModels( + providerName: RegisteredProvider, + ): Promise { + try { + if (!providerName) return []; + + return this.registry.listChatModels(providerName); + } catch (error) { + console.error( + "Smart Second Brain: Error fetching available models", + error, + ); + return []; + } + } + + async getThreadHistory(threadId: string): Promise { + try { + // Try to use agent if available to get history from checkpoint (more robust) + if (this.agent) { + try { + const history = await this.agent.getThreadHistory(threadId); + if (history) { + return history; + } + } catch (e) { + console.warn("Failed to get history from agent", e); + } + } + return null; + } catch (error) { + console.error("Smart Second Brain: Error fetching thread history", error); + return null; + } + } + + async getAllThreads(): Promise { + await this.chatManager.load(); + return this.chatManager.listThreads(); + } + + async deleteThread(threadId: string): Promise { + await this.chatManager.delete(threadId); + } + + async generateThreadTitle(threadId: string): Promise { + const agent = await this.ensureAgent().catch((e) => { + console.warn("Agent not initialized, cannot generate title"); + return null; + }); + + if (!agent) return; + + try { + await agent.generateTitle(threadId); + console.log(`Generated title for thread ${threadId}`); + + // Wait a bit for the title to be persisted + await new Promise((resolve) => setTimeout(resolve, 200)); + + // Try multiple ways to get the title: + // 1. Read from thread store (may have it in cache) + let snapshot = await this.chatManager.read(threadId, true); + console.log(`Read snapshot for thread ${threadId}:`, snapshot); + + // 2. If not found, try reading directly from in-memory storage + if (!snapshot?.title) { + const threadData = await this.chatManager.ensureThreadLoaded(threadId); + if (threadData?.title) { + console.log(`Title found in threadData: "${threadData.title}"`); + snapshot = { + threadId: threadData.threadId, + title: threadData.title, + metadata: threadData.metadata, + createdAt: threadData.createdAt, + updatedAt: threadData.updatedAt, + }; + } + } + + if (snapshot?.title) { + console.log(`Title found: "${snapshot.title}", renaming file...`); + await this.chatManager.renameChatFile(threadId, snapshot.title); + } else { + console.warn( + `No title found for thread ${threadId} after generation. Waiting longer and retrying...`, + ); + // Wait longer and try again + await new Promise((resolve) => setTimeout(resolve, 1000)); + snapshot = await this.chatManager.read(threadId, true); + if (snapshot?.title) { + console.log( + `Title found on retry: "${snapshot.title}", renaming file...`, + ); + await this.chatManager.renameChatFile(threadId, snapshot.title); + } else { + console.error( + `Title still not found for thread ${threadId} after retry`, + ); + } + } + } catch (error) { + console.error(`Error generating title for thread ${threadId}:`, error); + } + } + + cleanup(): void { + // Restore original fetch if it was patched + if ((window as any)._originalFetch) { + window.fetch = (window as any)._originalFetch; + delete (window as any)._originalFetch; + } + + // Cleanup if needed + this.agent = null; + } + + async createNewChat(): Promise { + const threadId = createThreadId(); + const now = Date.now(); + + const folder = getData().targetFolder; + + // Ensure folder exists + if (!(await this.plugin.app.vault.adapter.exists(folder))) { + await this.plugin.app.vault.createFolder(folder); + } + + const path = normalizePath(`${folder}/${threadId}.chat`); + + // Initialize with valid thread data structure + const initialData = { + threadId, + createdAt: now, + updatedAt: now, + checkpoints: {}, + writes: {}, + }; + + // Create file directly and open it + const file = await this.plugin.app.vault.create( + path, + JSON.stringify(initialData, null, 2), + ); + await this.plugin.app.workspace.getLeaf(false).openFile(file); + } + + async openLatestChat(): Promise { + const threads = await this.chatManager.listThreads(); + + if (threads.length === 0) { + await this.createNewChat(); + return; + } + + const latestThread = threads[0]; + const folder = getData().targetFolder; + const path = normalizePath(`${folder}/${latestThread.threadId}.chat`); + const file = this.plugin.app.vault.getAbstractFileByPath(path); + + if (file) { + await this.plugin.app.workspace.getLeaf(false).openFile(file as any); + } else { + await this.createNewChat(); + } + } +} diff --git a/src/agent/ObsidianChatManager.ts b/src/agent/ObsidianChatManager.ts new file mode 100644 index 00000000..dc7c3def --- /dev/null +++ b/src/agent/ObsidianChatManager.ts @@ -0,0 +1,637 @@ +import { + BaseCheckpointSaver, + type Checkpoint, + type CheckpointMetadata, + type CheckpointTuple, + type PendingWrite, + type CheckpointListOptions, +} from "@langchain/langgraph-checkpoint"; +import type { RunnableConfig } from "@langchain/core/runnables"; +import { + Plugin, + debounce, + TFile, + normalizePath, + type DataAdapter, +} from "obsidian"; +import type SecondBrainPlugin from "../main"; +import { type ThreadStore, type ThreadSnapshot } from "papa-ts"; +import { getData } from "../stores/dataStore.svelte"; + +interface CheckpointEntry { + checkpoint: Checkpoint; + metadata: CheckpointMetadata; + parentConfig?: RunnableConfig; +} + +interface ThreadData { + // Metadata (ThreadSnapshot) + threadId: string; + title?: string; + metadata?: Record; + createdAt: number; + updatedAt: number; + + // Checkpoint data + checkpoints: Record; + writes: Record; // checkpoint_id -> writes +} + +export class ObsidianChatManager extends BaseCheckpointSaver { + private plugin: SecondBrainPlugin; + private adapter: DataAdapter; + + // In-memory cache: thread_id -> ThreadData (Loaded on demand) + private storage: Map = new Map(); + + // Index cache: thread_id -> ThreadSnapshot (Loaded on startup) + private threadIndex: Map = new Map(); + + // Path cache: thread_id -> file_path (Optimizes file lookups) + private filePathCache: Map = new Map(); + + private indexLoaded: boolean = false; + + constructor(plugin: SecondBrainPlugin) { + super(); + this.plugin = plugin; + this.adapter = plugin.app.vault.adapter; + } + + // --- File System Helpers --- + + private getChatFolder(): string { + const data = getData(); + return data.targetFolder; + } + + private getIndexPath(): string { + const configDir = (this.plugin.app.vault as any).configDir || ".obsidian"; + return `${configDir}/plugins/${this.plugin.manifest.id}/data/threads.json`; + } + + private async ensureFolder(): Promise { + const folder = this.getChatFolder(); + if (!(await this.adapter.exists(folder))) { + await this.adapter.mkdir(folder); + } + + // Ensure plugin data dir for index + const dataDir = `${(this.plugin.app.vault as any).configDir || ".obsidian"}/plugins/${this.plugin.manifest.id}/data`; + if (!(await this.adapter.exists(dataDir))) { + await this.adapter.mkdir(dataDir); + } + } + + private async resolveFilePath(threadId: string): Promise { + // Check cache first + if (this.filePathCache.has(threadId)) { + return this.filePathCache.get(threadId)!; + } + + const folder = this.getChatFolder(); + + // First try the default path + const defaultPath = `${folder}/${threadId}.chat`; + if (await this.adapter.exists(defaultPath)) { + this.filePathCache.set(threadId, defaultPath); + return defaultPath; + } + + // If not found, search for it (renamed files) + // Look for: "{Title} - {Timestamp}.chat" + // Timestamp is usually the part after "Chat " in the threadId + let timestampPart = ""; + if (threadId.startsWith("Chat ")) { + timestampPart = threadId.substring(5); + } + + try { + if (await this.adapter.exists(folder)) { + const result = await this.adapter.list(folder); + for (const file of result.files) { + if (!file.endsWith(".chat")) continue; + + // Check if file contains threadId (legacy check) + if (file.includes(threadId)) { + this.filePathCache.set(threadId, file); + return file; + } + + // Check for renamed files with matching timestamp + if (timestampPart && file.endsWith(` - ${timestampPart}.chat`)) { + this.filePathCache.set(threadId, file); + return file; + } + } + } + } catch (e) { + console.error(`Error searching for file with threadId ${threadId}:`, e); + } + + // Fallback to default path (will be created there if writing) + this.filePathCache.set(threadId, defaultPath); + return defaultPath; + } + + // --- Index Management --- + + async load(): Promise { + if (this.indexLoaded) return; + + await this.ensureFolder(); + const indexPath = this.getIndexPath(); + + try { + if (await this.adapter.exists(indexPath)) { + const content = await this.adapter.read(indexPath); + const snapshots = JSON.parse(content) as ThreadSnapshot[]; + this.threadIndex.clear(); + snapshots.forEach((s) => this.threadIndex.set(s.threadId, s)); + this.indexLoaded = true; + console.log( + `ObsidianChatManager: Loaded index with ${this.threadIndex.size} threads`, + ); + } else { + console.log("ObsidianChatManager: Index missing, rebuilding..."); + await this.rebuildIndex(); + } + } catch (e) { + console.error("Error loading chat index:", e); + } + } + + async rebuildIndex(): Promise { + const folder = this.getChatFolder(); + if (!(await this.adapter.exists(folder))) return; + + const result = await this.adapter.list(folder); + this.threadIndex.clear(); + this.filePathCache.clear(); + + for (const file of result.files) { + if (!file.endsWith(".chat")) continue; + + // Yield to event loop + await new Promise((resolve) => setTimeout(resolve, 0)); + + try { + const content = await this.adapter.read(file); + const data = JSON.parse(content) as ThreadData; + if (data && data.threadId) { + // Cache path + this.filePathCache.set(data.threadId, file); + + // Update index + this.threadIndex.set(data.threadId, { + threadId: data.threadId, + title: data.title, + metadata: data.metadata, + createdAt: data.createdAt, + updatedAt: data.updatedAt, + }); + } + } catch (e) { + console.error(`Failed to read ${file} during index rebuild:`, e); + } + } + + this.indexLoaded = true; + await this.saveIndex(); + } + + private async saveIndex() { + const indexPath = this.getIndexPath(); + const snapshots = Array.from(this.threadIndex.values()); + try { + await this.adapter.write(indexPath, JSON.stringify(snapshots, null, 2)); + } catch (e) { + console.error("Error saving chat index:", e); + } + } + + private saveIndexDebounced = debounce( + () => { + this.saveIndex(); + }, + 2000, + true, + ); + + // --- Thread Loading / Saving --- + + async ensureThreadLoaded(threadId: string): Promise { + if (this.storage.has(threadId)) return this.storage.get(threadId); + + const path = await this.resolveFilePath(threadId); + + try { + if (await this.adapter.exists(path)) { + const content = await this.adapter.read(path); + const data = JSON.parse(content) as ThreadData; + this.storage.set(threadId, data); + return data; + } + } catch (e) { + console.error(`Error loading thread ${threadId}:`, e); + } + return undefined; + } + + private createThreadData(threadId: string): ThreadData { + return { + threadId, + createdAt: Date.now(), + updatedAt: Date.now(), + checkpoints: {}, + writes: {}, + }; + } + + /** + * Creates a new thread and persists it to disk. + * Returns + **/ + + private async saveThread(threadId: string) { + const data = this.storage.get(threadId); + if (!data) return; + + await this.ensureFolder(); + const path = await this.resolveFilePath(threadId); + + try { + await this.adapter.write(path, JSON.stringify(data, null, 2)); + + // Update index + this.threadIndex.set(threadId, { + threadId: data.threadId, + title: data.title, + metadata: data.metadata, + createdAt: data.createdAt, + updatedAt: data.updatedAt, + }); + this.saveIndexDebounced(); + } catch (e) { + console.error(`Error saving thread ${threadId}:`, e); + } + } + + private saveDebounced = debounce( + (threadId: string) => { + this.saveThread(threadId); + }, + 1000, + true, + ); + + // --- ThreadStore Implementation --- + + async read( + threadId: string, + forceReload: boolean = false, + ): Promise { + if (!forceReload && this.threadIndex.has(threadId)) { + return this.threadIndex.get(threadId); + } + + const data = await this.ensureThreadLoaded(threadId); + if (!data) return undefined; + + const snapshot: ThreadSnapshot = { + threadId: data.threadId, + title: data.title, + metadata: data.metadata, + createdAt: data.createdAt, + updatedAt: data.updatedAt, + }; + + if (!this.threadIndex.has(threadId) || forceReload) { + this.threadIndex.set(threadId, snapshot); + } + + return snapshot; + } + + async write(snapshot: ThreadSnapshot): Promise { + let data = await this.ensureThreadLoaded(snapshot.threadId); + + if (!data) { + data = this.createThreadData(snapshot.threadId); + data.createdAt = snapshot.createdAt; + this.storage.set(snapshot.threadId, data); + } + + data.title = snapshot.title; + data.metadata = snapshot.metadata; + data.updatedAt = snapshot.updatedAt; + + this.saveDebounced(snapshot.threadId); + } + + async delete(threadId: string): Promise { + await this.deleteThread(threadId); + } + + async listThreads(): Promise { + await this.load(); + return Array.from(this.threadIndex.values()).sort( + (a, b) => b.updatedAt - a.updatedAt, + ); + } + + asThreadStore(): ThreadStore { + return { + read: this.read.bind(this), + write: this.write.bind(this), + delete: this.delete.bind(this), + list: this.listThreads.bind(this), + clear: this.clear.bind(this), + }; + } + + async clear(): Promise { + await this.load(); + const ids = Array.from(this.threadIndex.keys()); // Use index keys as source of truth + for (const id of ids) { + await this.deleteThread(id); + } + } + + // --- CheckpointSaver Implementation --- + + async getTuple(config: RunnableConfig): Promise { + const threadId = config.configurable?.thread_id; + if (!threadId) return undefined; + + const threadData = await this.ensureThreadLoaded(threadId); + if (!threadData) return undefined; + + const checkpointId = config.configurable?.checkpoint_id; + + if (checkpointId) { + const entry = threadData.checkpoints[checkpointId]; + if (!entry) return undefined; + + // For specific checkpoint, also include any error writes from child checkpoints + const pendingWrites = this.collectWritesWithErrors( + threadData, + checkpointId, + ); + + return { + config, + checkpoint: entry.checkpoint, + metadata: entry.metadata, + parentConfig: entry.parentConfig, + pendingWrites: pendingWrites as any, + }; + } + + const checkpoints = Object.values(threadData.checkpoints); + if (checkpoints.length === 0) return undefined; + + // Find latest by getting keys and sorting (could rely on insertion order if reliable, but timestamps/keys are safer) + // We use lex sort on keys (checkpoint_ids are usually lex-sortable uuids or similar) + const keys = Object.keys(threadData.checkpoints).sort().reverse(); + const latestId = keys[0]; + const entry = threadData.checkpoints[latestId]; + + // Collect writes from the latest checkpoint AND any error writes from subsequent checkpoints + const pendingWrites = this.collectWritesWithErrors(threadData, latestId); + + return { + config: { + ...config, + configurable: { ...config.configurable, checkpoint_id: latestId }, + }, + checkpoint: entry.checkpoint, + metadata: entry.metadata, + parentConfig: entry.parentConfig, + pendingWrites: pendingWrites as any, + }; + } + + /** + * Collects pending writes for a checkpoint, including error writes from child checkpoints. + * This is needed because errors are written to a child checkpoint that may not exist in the checkpoints map. + */ + private collectWritesWithErrors( + threadData: ThreadData, + checkpointId: string, + ): PendingWrite[] { + const writes: PendingWrite[] = []; + + // Add writes from the specific checkpoint + if (threadData.writes[checkpointId]) { + writes.push(...threadData.writes[checkpointId]); + } + + // Collect ALL error writes from the entire thread + // This is needed because each errored user message has its own error in a subsequent checkpoint + const allWriteKeys = Object.keys(threadData.writes).sort(); + for (const writeKey of allWriteKeys) { + // Skip the checkpoint we already added + if (writeKey === checkpointId) continue; + + const checkpointWrites = threadData.writes[writeKey]; + for (const write of checkpointWrites) { + if ( + Array.isArray(write) && + (write[0] === "__error__" || write[1] === "__error__") + ) { + writes.push(write); + } + } + } + + return writes; + } + + async *list( + config: RunnableConfig, + options?: CheckpointListOptions, + ): AsyncGenerator { + const threadId = config.configurable?.thread_id; + if (!threadId) return; + + const threadData = await this.ensureThreadLoaded(threadId); + if (!threadData) return; + + const keys = Object.keys(threadData.checkpoints).sort().reverse(); + + for (const key of keys) { + const entry = threadData.checkpoints[key]; + if ( + options?.before && + options.before.configurable?.checkpoint_id && + key >= options.before.configurable.checkpoint_id + ) { + continue; + } + + yield { + config: { + ...config, + configurable: { ...config.configurable, checkpoint_id: key }, + }, + checkpoint: entry.checkpoint, + metadata: entry.metadata, + parentConfig: entry.parentConfig, + pendingWrites: (threadData.writes[key] || []) as any, + }; + + if (options?.limit && --options.limit <= 0) break; + } + } + + async put( + config: RunnableConfig, + checkpoint: Checkpoint, + metadata: CheckpointMetadata, + newVersions: Record, + ): Promise { + const threadId = config.configurable?.thread_id; + const checkpointId = checkpoint.id; + if (!threadId || !checkpointId) return config; + + let threadData = await this.ensureThreadLoaded(threadId); + if (!threadData) { + threadData = this.createThreadData(threadId); + this.storage.set(threadId, threadData); + } + + // Sanitize to plain JSON + const plainCheckpoint = JSON.parse(JSON.stringify(checkpoint)); + const plainMetadata = JSON.parse(JSON.stringify(metadata)); + + threadData.checkpoints[checkpointId] = { + checkpoint: plainCheckpoint, + metadata: plainMetadata, + parentConfig: config, + }; + + threadData.updatedAt = Date.now(); + this.saveDebounced(threadId); + + // Update index cache immediately + if (this.threadIndex.has(threadId)) { + const snap = this.threadIndex.get(threadId)!; + snap.updatedAt = threadData.updatedAt; + } else { + this.threadIndex.set(threadId, { + threadId: threadData.threadId, + title: threadData.title, + metadata: threadData.metadata, + createdAt: threadData.createdAt, + updatedAt: threadData.updatedAt, + }); + } + // Persist index changes debounced + this.saveIndexDebounced(); + + return { + ...config, + configurable: { + ...config.configurable, + checkpoint_id: checkpointId, + }, + }; + } + + async putWrites( + config: RunnableConfig, + writes: PendingWrite[], + taskId: string, + ): Promise { + const threadId = config.configurable?.thread_id; + const checkpointId = config.configurable?.checkpoint_id; + + if (!threadId || !checkpointId) return; + + let threadData = await this.ensureThreadLoaded(threadId); + if (!threadData) { + threadData = this.createThreadData(threadId); + this.storage.set(threadId, threadData); + } + + if (!threadData.writes[checkpointId]) { + threadData.writes[checkpointId] = []; + } + + threadData.writes[checkpointId].push(...writes); + threadData.updatedAt = Date.now(); + this.saveDebounced(threadId); + + if (this.threadIndex.has(threadId)) { + this.threadIndex.get(threadId)!.updatedAt = threadData.updatedAt; + this.saveIndexDebounced(); + } + } + + async deleteThread(threadId: string): Promise { + // Remove from memory + this.storage.delete(threadId); + this.threadIndex.delete(threadId); + this.filePathCache.delete(threadId); + this.saveIndexDebounced(); + + // Remove from disk + const path = await this.resolveFilePath(threadId); + try { + if (await this.adapter.exists(path)) { + await this.adapter.remove(path); + } + } catch (e) { + console.error(`Error deleting thread ${threadId}:`, e); + } + } + + // --- Utilities --- + + private sanitizeFileName(title: string): string { + return title + .replace(/[<>:"/\\|?*]/g, "-") + .replace(/\s+/g, " ") + .trim() + .substring(0, 100); + } + + async renameChatFile(threadId: string, title: string): Promise { + if (!title || !title.trim()) return; + + try { + const oldPath = await this.resolveFilePath(threadId); + const file = this.plugin.app.vault.getAbstractFileByPath(oldPath); + + if (!file || !(file instanceof TFile)) { + console.warn(`renameChatFile: File not found: ${oldPath}`); + return; + } + + const sanitizedTitle = this.sanitizeFileName(title); + const dateTimePart = threadId.startsWith("Chat ") + ? threadId.substring(5) + : threadId; + const newFileName = `${sanitizedTitle} - ${dateTimePart}.chat`; + + if (file.name === newFileName) return; + + const folder = this.getChatFolder(); + const newPath = normalizePath(`${folder}/${newFileName}`); + + if (await this.adapter.exists(newPath)) { + console.warn(`renameChatFile: Target file already exists: ${newPath}`); + return; + } + + await this.plugin.app.fileManager.renameFile(file, newPath); + + // Update cache with new path + this.filePathCache.set(threadId, newPath); + console.log(`renameChatFile: Successfully renamed to ${newPath}`); + } catch (error) { + console.error(`Error renaming chat file for thread ${threadId}:`, error); + } + } +} diff --git a/src/agent/prompts.ts b/src/agent/prompts.ts new file mode 100644 index 00000000..62293f04 --- /dev/null +++ b/src/agent/prompts.ts @@ -0,0 +1,87 @@ +export const createSystemPrompt = (hasChartsPlugin: boolean) => `# Role +You are a privacy-aware assistant integrated into Obsidian. You help users search and understand their notes. + +# Important Formatting Rules +- **Wiki Links**: When mentioning note names, ALWAYS use raw Obsidian wiki link syntax: [[Note Name]] + - CORRECT: Check out [[My Daily Notes]] for more info + - WRONG: Check out \`[[My Daily Notes]]\` for more info + - NEVER wrap wiki links in backticks - they must be raw so Obsidian can render them as clickable links +- Only use backticks (\`) for actual code, commands, or technical terms - NOT for note references + +# Tools & Capabilities +- **search_notes**: Finds relevant information from the user's notes. Note that this tool ONLY returns file paths and metadata, not content. +- **read_note**: Reads the full content of a specific note. Use only after identifying it as relevant. +- **get_all_tags**: Discovers available tags in the vault. +- **get_properties**: Retrieves frontmatter properties from notes or discovers available property keys. +- **execute_dataview_query**: Executes Dataview DQL queries for data analysis. + +# Strategy for Finding Notes +1. **Unknown Organization**: If the user asks for a category of notes (e.g. "daily notes", "meetings", "books", "ideas") and you don't know how they are organized: + - Call \`get_all_tags\` FIRST to check if a relevant tag exists (e.g. #daily, #meeting, #book). + - ALSO call \`get_properties\` to check if there are relevant frontmatter properties (e.g. "type", "category", "status"). + - If you find a matching tag or property, use it to filter your Dataview query. + - If no relevant tag or property is found, call \`search_notes\` with a broad term to find example files and see their paths/names/properties. + - **Do NOT guess** tag names, property keys, or folder paths without verifying first. + +2. **Verification**: Before constructing a Dataview query, ALWAYS verify which tags, properties, folders, or keywords actually exist using the steps above. + +3. **Reading Content**: + - \`search_notes\` will give you a list of potential matches with metadata. + - If you need to read the full content of a note to answer a question, use \`read_note\` with the specific file path from the search results. + - If you need to aggregate data (e.g. list tasks, summarize properties), prefer using \`execute_dataview_query\`. + +# Output Options for Dataview & Math + +## 1. Data Analysis +If you need to SEE the results to answer a question or perform analysis, use the \`execute_dataview_query\` tool (supports DQL only). + +## 2. Displaying Lists/Tables +If you want to SHOW the user a list or table (e.g. 'List all my books'), simply output the Dataview DQL query in a markdown code block: +\`\`\`dataview +QUERY +\`\`\` +The chat interface will render this automatically. + +${ + hasChartsPlugin + ? `## 3. Displaying Charts +You can create charts using \`dataviewjs\`. The user has the \`obsidian-charts\` plugin installed, so you can output a \`dataviewjs\` code block that uses \`window.renderChart\`. +**Important**: \`window.renderChart\` takes exactly two arguments: the chart data object and the container element. The chart data object must follow the standard Chart.js format (type, data, options). Use Obsidian CSS variables (e.g., \`var(--interactive-accent)\`) for chart colors to match the theme. + +Example: +\`\`\`dataviewjs +const pages = dv.pages('#games'); +const labels = pages.map(p => p.file.name).values; +const data = pages.map(p => p.rating).values; + +const accentColor = getComputedStyle(document.body).getPropertyValue('--interactive-accent').trim(); +const chartData = { + type: 'bar', + data: { + labels: labels, + datasets: [{ + label: 'Game Ratings', + data: data, + backgroundColor: accentColor, + borderColor: accentColor + }] + } +} +window.renderChart(chartData, this.container); +\`\`\` +The chat interface will render this chart automatically.` + : "" +} + +## ${hasChartsPlugin ? "4" : "3"}. Math/LaTeX +Supports MathJax rendering. +- Use single dollar signs for inline math: $E=mc^2$ +- Use double dollar signs for block math: + $$ + \int x dx + $$ +- **IMPORTANT**: Do NOT wrap the math in markdown code blocks (like \`\`\`latex or \` ). The renderer needs the raw $ or $$ delimiters to detect and render the math. + +When generating a view (list, table${hasChartsPlugin ? ", or chart" : ""}) for the user, introduce it as "Here is the list:" or "I have generated the view below:", rather than telling the user to run or use the query.`; + +export const AGENT_SYSTEM_PROMPT = createSystemPrompt(false); // Default for backward compatibility diff --git a/src/components/Chat/ChatList.svelte b/src/components/Chat/ChatList.svelte new file mode 100644 index 00000000..5a331905 --- /dev/null +++ b/src/components/Chat/ChatList.svelte @@ -0,0 +1,90 @@ + + +
+ {#if chats.length > 0} +
+ Recent +
+ {/if} + {#each chats as chat} + + + +
await activateNewSession(chat.id)} + onmouseenter={() => (hoveredChatId = chat.id)} + onmouseleave={() => (hoveredChatId = null)} + > +
{chat.title}
+
+ {formatDDMMYY_HHMM(chat.lastAccessed)} + {#if hoveredChatId === chat.id} +
e.stopPropagation()}> +
await deleteChat(chat.id)} + >
+
+ {/if} +
+
+ {/each} +
diff --git a/src/components/Chat/Input.svelte b/src/components/Chat/Input.svelte old mode 100644 new mode 100755 index bd67553d..662f5b7c --- a/src/components/Chat/Input.svelte +++ b/src/components/Chat/Input.svelte @@ -1,148 +1,358 @@ - - - -
-
onFocusChange?.(true)} + onfocusout={() => onFocusChange?.(false)} +> + + +
+
+ {#each files as file} +
+ {#if file.type === "text/plain"} +
+ {:else if file.type === "application/json"} +
+ {/if} +
+ {file.name} +
+ + +
removeAttachedFile(file)} + class="hover:bg-[buttonface] flex items-center justify-center h-4 w-4 bg-white rounded-sm mr-1 my-1" + >
+
+ {/each}
- {#if $chatHistory.length > 1} - -
-
- + + - {:else} -
- + + +
+ + onFileAttachment(event)} + /> + +
+ {#if !messenger.session || messenger.session.messageState === MessageState.idle} + + {:else if messenger.session.messageState === MessageState.answering} + + {/if} +
- {/if} +
+ + +
+ AI can make mistakes. Please check important information. +
+ + diff --git a/src/components/Chat/MessageContainer.svelte b/src/components/Chat/MessageContainer.svelte old mode 100644 new mode 100755 index 458267a8..06c89271 --- a/src/components/Chat/MessageContainer.svelte +++ b/src/components/Chat/MessageContainer.svelte @@ -1,31 +1,314 @@ -{#if role === 'User'} - {#if $data.isChatComfy} -
- -
- +
+ +
+ {#if !messages || messages.length === 0} + +
+
+ +
+

Start a new conversation

+

+ Ask me anything about your notes. +

-
- {:else} -
-
{$t('chat.user')}
- -
- {/if} -{:else if $data.isChatComfy} -
- -
-{:else} -
-
{$t('chat.assistant')}
- + {:else} + {#each messages as messagePair, index} +
+
+ +
+ + +
console.log("redo Message")} + >
+ + + +
console.log("split")} + >
+ + + +
console.log("edit")} + >
+ + + +
+ copyToClipboard( + messagePair.userMessage.content, + )} + >
+
+
+
+
+ + {#if messagePair.assistantMessage.toolCalls?.length} + + setToolsOpen(messagePair.id, open)} + /> + {/if} + + + {#if messagePair.assistantMessage.state === AssistantState.streaming && !messagePair.assistantMessage.content} + + {:else if messagePair.assistantMessage.content || messagePair.assistantMessage.state === AssistantState.cancelled || messagePair.assistantMessage.state === AssistantState.error} +
+ {:else if messagePair.assistantMessage.state === AssistantState.idle || messagePair.assistantMessage.state === AssistantState.streaming} + + {#if !messagePair.assistantMessage.toolCalls?.length} + + {/if} + {/if} + + {#if !(messagePair.assistantMessage.state === AssistantState.streaming)} +
+ + +
+ copyToClipboard( + messagePair.assistantMessage + .content, + )} + >
+ + +
branchOff(messagePair.id)} + > + > +
+ + +
+ console.log("redo Message")} + >
+
+ {/if} +
+
+ {/each} + {/if}
-{/if} +
+ + diff --git a/src/components/Chat/QuickSettingsDrawer.svelte b/src/components/Chat/QuickSettingsDrawer.svelte old mode 100644 new mode 100755 index 90f24af5..8c657e1f --- a/src/components/Chat/QuickSettingsDrawer.svelte +++ b/src/components/Chat/QuickSettingsDrawer.svelte @@ -1,94 +1,75 @@ - + +
+
onToggle((e.target as HTMLDetailsElement).open)} + class="w-full" + > + + + + {toolStatus === "running" ? "⏳" : "🛠️"} + + + {summaryText} + + +
+ {#each toolCalls as toolCall (toolCall.id)} +
+
+ + + {#if toolCall.status === "running"} + ⏳ + {:else if toolCall.status === "completed"} + ✅ + {:else} + ❌ + {/if} + + + {formatToolName(toolCall.name)} + + + +
+
+ Input: + {#if formatToolInput(toolCall.input).length > 0} +
+ {#each formatToolInput(toolCall.input) as { key, value } (key)} +
+ {key}: +
+
+ {/each} +
+ {:else} + (empty) + {/if} +
+ {#if toolCall.output !== undefined} +
+ Output: +
+
+ {/if} +
+
+
+ {/each} +
+
+
diff --git a/src/components/Logos/Logo.svelte b/src/components/Logos/Logo.svelte old mode 100644 new mode 100755 index 429edae0..2bbc4b57 --- a/src/components/Logos/Logo.svelte +++ b/src/components/Logos/Logo.svelte @@ -1,9 +1,5 @@ - - diff --git a/src/components/Logos/LogoDetailed.svelte b/src/components/Logos/LogoDetailed.svelte old mode 100644 new mode 100755 index 55a5f480..b4253232 --- a/src/components/Logos/LogoDetailed.svelte +++ b/src/components/Logos/LogoDetailed.svelte @@ -1,5 +1,5 @@ + import { onMount } from "svelte"; + import SettingContainer from "../Settings/SettingContainer.svelte"; + import ButtonComponent from "../base/Button.svelte"; + import { getData } from "../../stores/dataStore.svelte"; + import type { ExcludeFoldersModal } from "./ExcludeFoldersModal"; + import Button from "../base/Button.svelte"; + import Dropdown from "../base/Dropdown.svelte"; + import Toggle from "../base/Toggle.svelte"; + import { prepareFuzzySearch, TAbstractFile } from "obsidian"; + import FolderSuggest from "./FolderSuggest.svelte"; + import { getPlugin } from "../../stores/state.svelte"; + + interface Props { + modal: ExcludeFoldersModal; + } + + const plugin = getPlugin(); + + const data = getData(); + + const suggestionLength: number = 100; + + let { modal }: Props = $props(); + + //TODO: Finish implementing modes + + export const modes = ["File/Folder", "Filetyp"] as const; + + let exclusionMode: (typeof modes)[number] = $state("File/Folder"); + + function matchFilesFolders(query: string): TAbstractFile[] { + let allFiles = plugin.app.vault.getAllLoadedFiles(); + + if (!query) { + return allFiles.slice(0, 10); + } + + const fuzzySearch = prepareFuzzySearch(query); + + const matches = allFiles + .map((file) => ({ + file, + match: fuzzySearch(file.path), + })) + .filter((item) => item.match) + .sort((a, b) => b.match!.score - a.match!.score) + .map((item) => item.file); + + return matches; + } + + function addExcludeFolder(folder: string) { + if (folder.trim()) { + data.addIndexList(folder.trim()); + papaState.set("settings-change"); + } + } + + function removeExcludeFolder(folder: string) { + data.removeIndexList(folder); + papaState.set("settings-change"); + } + + + + + + diff --git a/src/components/Modal/ExcludeFoldersModal.ts b/src/components/Modal/ExcludeFoldersModal.ts new file mode 100644 index 00000000..670a228f --- /dev/null +++ b/src/components/Modal/ExcludeFoldersModal.ts @@ -0,0 +1,25 @@ +import { App, Modal } from "obsidian"; +import ExcludeFoldersComponent from "./ExcludeFoldersModal.svelte"; +import { mount } from "svelte"; + +export class ExcludeFoldersModal extends Modal { + component!: ExcludeFoldersComponent; + + constructor(app: App) { + super(app); + } + + onOpen() { + this.component = mount(ExcludeFoldersComponent, { + target: this.contentEl, + props: { + modal: this, + }, + }); + } + + onClose() { + const { contentEl } = this; + contentEl.empty(); + } +} diff --git a/src/components/Modal/FolderSuggest.svelte b/src/components/Modal/FolderSuggest.svelte new file mode 100644 index 00000000..baa5fe98 --- /dev/null +++ b/src/components/Modal/FolderSuggest.svelte @@ -0,0 +1,97 @@ + + + diff --git a/src/components/Modal/RemoveModal.svelte b/src/components/Modal/RemoveModal.svelte old mode 100644 new mode 100755 index 3f4402c9..405f9125 --- a/src/components/Modal/RemoveModal.svelte +++ b/src/components/Modal/RemoveModal.svelte @@ -1,22 +1,24 @@ - --> - + diff --git a/src/components/Modal/RemoveModal.ts b/src/components/Modal/RemoveModal.ts old mode 100644 new mode 100755 index e8365dec..17fdd743 --- a/src/components/Modal/RemoveModal.ts +++ b/src/components/Modal/RemoveModal.ts @@ -1,23 +1,24 @@ -import { Modal, App } from 'obsidian'; -import RemoveComponent from './RemoveModal.svelte'; +import { Modal, App } from "obsidian"; +import RemoveComponent from "./RemoveModal.svelte"; +import { mount } from "svelte"; export class RemoveModal extends Modal { - component: RemoveComponent; - constructor(app: App) { - super(app); - } + component: RemoveComponent; + constructor(app: App) { + super(app); + } - onOpen() { - new RemoveComponent({ - target: this.contentEl, - props: { - modal: this, - }, - }); - } + onOpen() { + mount(RemoveComponent, { + target: this.contentEl, + props: { + modal: this, + }, + }); + } - onClose() { - const { contentEl } = this; - contentEl.empty(); - } + onClose() { + const { contentEl } = this; + contentEl.empty(); + } } diff --git a/src/components/QueryClientProvider.svelte b/src/components/QueryClientProvider.svelte new file mode 100644 index 00000000..cb6db0db --- /dev/null +++ b/src/components/QueryClientProvider.svelte @@ -0,0 +1,18 @@ + + + + {@const Component = component} + + diff --git a/src/components/Settings/AuthConfigFields.svelte b/src/components/Settings/AuthConfigFields.svelte new file mode 100644 index 00000000..f40dcf9c --- /dev/null +++ b/src/components/Settings/AuthConfigFields.svelte @@ -0,0 +1,50 @@ + + +{#if authParams} + {#each Object.entries(fieldMeta).filter( ([_, meta]) => (showAdvanced ? true : meta.required), ) as [fieldKey, meta]} + + { + (data.setProviderAuthParam as any)( + provider, + fieldKey, + value, + ); + invalidateAuthState(provider); + }} + /> + + {/each} +{/if} diff --git a/src/components/Settings/ConfiguredProvider.svelte b/src/components/Settings/ConfiguredProvider.svelte new file mode 100644 index 00000000..b4971860 --- /dev/null +++ b/src/components/Settings/ConfiguredProvider.svelte @@ -0,0 +1,142 @@ + + + + onAccordionClick(configuredProvider)} + class="sync-exclude-folder w-[-webkit-fill-available] !mr-0" + > + +
+ + {configuredProvider} + {#if query.data?.success} +
+ {:else} - + {/if} diff --git a/src/components/base/DotAnimation.svelte b/src/components/base/DotAnimation.svelte old mode 100644 new mode 100755 index fedca726..3c490fba --- a/src/components/base/DotAnimation.svelte +++ b/src/components/base/DotAnimation.svelte @@ -1,8 +1,8 @@ {#each ['', '.', '..', '...'] as sequence, i} diff --git a/src/components/base/Dropdown.svelte b/src/components/base/Dropdown.svelte old mode 100644 new mode 100755 index 13b41a23..efe4dbce --- a/src/components/base/Dropdown.svelte +++ b/src/components/base/Dropdown.svelte @@ -1,11 +1,38 @@ - + + diff --git a/src/components/base/FilePopover.svelte b/src/components/base/FilePopover.svelte new file mode 100644 index 00000000..d4cefa84 --- /dev/null +++ b/src/components/base/FilePopover.svelte @@ -0,0 +1,83 @@ + + + + + console.log(e.currentTarget.value)} + class="sr-only" + /> + + + {#each filteredFiles as file, i (i + file.basename)} + + {#snippet children({ selected })} +
+
+ {file.basename} +
+
+ {file.parent?.path} +
+
+ {/snippet} +
+ {:else} + No match found. + {/each} +
+
+
diff --git a/src/components/base/Icon.svelte b/src/components/base/Icon.svelte new file mode 100644 index 00000000..e5f9df13 --- /dev/null +++ b/src/components/base/Icon.svelte @@ -0,0 +1,28 @@ + + +
console.log(e)} + class={"flex items-center " + className} + style={"--icon-size: " + size} + {onclick} +>
diff --git a/src/components/base/LoadingAnimation.svelte b/src/components/base/LoadingAnimation.svelte old mode 100644 new mode 100755 diff --git a/src/components/base/ProgressBar.svelte b/src/components/base/ProgressBar.svelte old mode 100644 new mode 100755 index c3976dbf..64694e5f --- a/src/components/base/ProgressBar.svelte +++ b/src/components/base/ProgressBar.svelte @@ -1,14 +1,21 @@ +> + + + + + diff --git a/src/utils/dataValidation.ts b/src/utils/dataValidation.ts new file mode 100644 index 00000000..6923f69d --- /dev/null +++ b/src/utils/dataValidation.ts @@ -0,0 +1,715 @@ +import { Prompts, type Language } from "papa-ts"; +import { registeredProviders, type RegisteredProvider } from "../types/providers"; +import type { PluginData } from "../main"; +import type { ProviderConfigs, GetProviderConfig, GetProviderAuth } from "../types/providers"; +import { DEFAULT_SETTINGS, DEFAULT_PROVIDER_CONFIGS } from "../constants/defaults"; + +/** + * Validation result type + */ +export interface ValidationResult { + isValid: boolean; + errors: string[]; + warnings: string[]; + data?: any; // The corrected/validated data +} + +/** + * Validates a string value + */ +function validateString(value: unknown, fieldName: string, required: boolean = true): ValidationResult { + const errors: string[] = []; + + if (value === undefined || value === null) { + if (required) { + errors.push(`${fieldName} is required`); + } + return { isValid: !required, errors, warnings: [] }; + } + + if (typeof value !== "string") { + errors.push(`${fieldName} must be a string, got ${typeof value}`); + return { isValid: false, errors, warnings: [] }; + } + + return { isValid: true, errors: [], warnings: [], data: value }; +} + +/** + * Validates a boolean value + */ +function validateBoolean(value: unknown, fieldName: string, defaultValue: boolean): ValidationResult { + if (value === undefined || value === null) { + return { isValid: true, errors: [], warnings: [], data: defaultValue }; + } + + if (typeof value !== "boolean") { + return { + isValid: true, + errors: [], + warnings: [`${fieldName} should be boolean, got ${typeof value}. Using default: ${defaultValue}`], + data: defaultValue, + }; + } + + return { isValid: true, errors: [], warnings: [], data: value }; +} + +/** + * Validates a number value + */ +function validateNumber(value: unknown, fieldName: string, min?: number, max?: number): ValidationResult { + const errors: string[] = []; + const warnings: string[] = []; + + if (value === undefined || value === null || typeof value !== "number" || isNaN(value)) { + errors.push(`${fieldName} must be a valid number`); + return { isValid: false, errors, warnings }; + } + + if (min !== undefined && value < min) { + warnings.push(`${fieldName} is below minimum ${min}, clamping to ${min}`); + return { isValid: true, errors: [], warnings, data: min }; + } + + if (max !== undefined && value > max) { + warnings.push(`${fieldName} is above maximum ${max}, clamping to ${max}`); + return { isValid: true, errors: [], warnings, data: max }; + } + + return { isValid: true, errors: [], warnings: [], data: value }; +} + +/** + * Validates an array of strings + */ +function validateStringArray(value: unknown, fieldName: string): ValidationResult { + const errors: string[] = []; + const warnings: string[] = []; + + if (value === undefined || value === null) { + return { isValid: true, errors: [], warnings: [], data: [] }; + } + + if (!Array.isArray(value)) { + warnings.push(`${fieldName} should be an array, got ${typeof value}. Using empty array.`); + return { isValid: true, errors: [], warnings, data: [] }; + } + + const validStrings = value.filter((item) => typeof item === "string"); + const invalidCount = value.length - validStrings.length; + + if (invalidCount > 0) { + warnings.push(`${fieldName} contained ${invalidCount} non-string items that were filtered out`); + } + + return { isValid: true, errors: [], warnings, data: validStrings }; +} + +/** + * Validates a Language value + */ +function validateLanguage(value: unknown, fieldName: string): ValidationResult { + const validLanguages = ["en", "de"]; // Add more as needed + + if (value === undefined || value === null) { + return { isValid: true, errors: [], warnings: [], data: "en" }; + } + + if (typeof value !== "string" || !validLanguages.includes(value)) { + return { + isValid: true, + errors: [], + warnings: [`${fieldName} "${value}" is not valid. Using default: en`], + data: "en", + }; + } + + return { isValid: true, errors: [], warnings: [], data: value as Language }; +} + +/** + * Validates embedding model configuration + */ +function validateEmbedModelConfig(value: unknown, modelName: string): ValidationResult { + const errors: string[] = []; + const warnings: string[] = []; + + if (!value || typeof value !== "object") { + errors.push(`Embed model config for ${modelName} must be an object`); + return { isValid: false, errors, warnings }; + } + + const config = value as any; + const thresholdValidation = validateNumber(config.similarityThreshold, `${modelName}.similarityThreshold`, 0, 1); + + if (!thresholdValidation.isValid) { + errors.push(...thresholdValidation.errors); + return { + isValid: false, + errors, + warnings: [...warnings, ...thresholdValidation.warnings], + }; + } + + return { + isValid: true, + errors: [], + warnings: [...warnings, ...thresholdValidation.warnings], + data: { + similarityThreshold: thresholdValidation.data, + }, + }; +} + +/** + * Validates generation model configuration + */ +function validateGenModelConfig(value: unknown, modelName: string): ValidationResult { + const errors: string[] = []; + const warnings: string[] = []; + + if (!value || typeof value !== "object") { + errors.push(`Gen model config for ${modelName} must be an object`); + return { isValid: false, errors, warnings }; + } + + const config = value as any; + const tempValidation = validateNumber(config.temperature, `${modelName}.temperature`, 0, 2); + const contextValidation = validateNumber(config.contextWindow, `${modelName}.contextWindow`, 1); + + if (!tempValidation.isValid || !contextValidation.isValid) { + errors.push(...tempValidation.errors, ...contextValidation.errors); + return { + isValid: false, + errors, + warnings: [...warnings, ...tempValidation.warnings, ...contextValidation.warnings], + }; + } + + return { + isValid: true, + errors: [], + warnings: [...warnings, ...tempValidation.warnings, ...contextValidation.warnings], + data: { + temperature: tempValidation.data, + contextWindow: contextValidation.data, + }, + }; +} + +/** + * Validates a Map or object of models + */ +function validateModelMap( + value: unknown, + validateModelFn: (value: unknown, modelName: string) => ValidationResult, + defaultMap: Map, + mapName: string, +): ValidationResult { + const errors: string[] = []; + const warnings: string[] = []; + const validatedMap = new Map(); + + // If Map was serialized to object (happens in storage), convert back + if (value && typeof value === "object" && !value.entries && !value.size) { + // Handle plain object conversion to Map + try { + for (const [key, modelConfig] of Object.entries(value as Record)) { + const validation = validateModelFn(modelConfig, `${mapName}.${key}`); + if (validation.isValid) { + validatedMap.set(key, validation.data as T); + warnings.push(...validation.warnings); + } else { + warnings.push(`Skipping invalid model config for ${key}: ${validation.errors.join(", ")}`); + } + } + } catch (e) { + warnings.push(`Error converting object to Map: ${e}. Using defaults.`); + } + } else if (value instanceof Map) { + // Handle actual Map instance + try { + for (const [key, modelConfig] of value.entries()) { + const validation = validateModelFn(modelConfig, `${mapName}.${key}`); + if (validation.isValid) { + validatedMap.set(key, validation.data as T); + warnings.push(...validation.warnings); + } else { + warnings.push(`Skipping invalid model config for ${key}: ${validation.errors.join(", ")}`); + } + } + } catch (e) { + warnings.push(`Error processing Map: ${e}. Using defaults.`); + } + } else { + warnings.push(`${mapName} is not a valid Map or object. Using defaults.`); + } + + // Ensure we have at least the default models + for (const [key, value] of defaultMap.entries()) { + if (!validatedMap.has(key)) { + validatedMap.set(key, value); + } + } + + return { + isValid: true, // We can always fall back to defaults + errors, + warnings, + data: validatedMap, + }; +} + +/** + * Validates the provider auth configuration + */ +function validateProviderAuth(provider: T, value: unknown): ValidationResult { + const errors: string[] = []; + const warnings: string[] = []; + const validatedAuth: Record = {}; + + if (!value || typeof value !== "object") { + warnings.push(`Provider auth for ${provider} is missing or invalid, using defaults.`); + return { + isValid: true, + errors, + warnings, + data: { ...DEFAULT_PROVIDER_CONFIGS[provider].providerAuth }, + }; + } + + const config = value as Record; + const defaultAuth = DEFAULT_PROVIDER_CONFIGS[provider].providerAuth; + + // Validate each auth field + for (const [key, defaultValue] of Object.entries(defaultAuth)) { + const authValue = config[key]; + const validation = validateString(authValue, `${provider}.providerAuth.${key}`, false); + + if (validation.isValid && validation.data !== undefined) { + validatedAuth[key] = validation.data; + } else { + validatedAuth[key] = defaultValue as string; + if (validation.warnings.length > 0) { + warnings.push(...validation.warnings); + } + } + } + + return { + isValid: true, + errors, + warnings, + data: validatedAuth as GetProviderAuth, + }; +} + +/** + * Validates a single provider configuration + */ +function validateProviderConfig(provider: T, value: unknown): ValidationResult { + const errors: string[] = []; + const warnings: string[] = []; + + if (!value || typeof value !== "object") { + errors.push(`Provider config for ${provider} must be an object`); + return { + isValid: true, + errors, + warnings: [...warnings, `Using default config for ${provider}`], + data: DEFAULT_PROVIDER_CONFIGS[provider], + }; + } + + const config = value as any; + const defaultConfig = DEFAULT_PROVIDER_CONFIGS[provider]; + const validatedConfig: any = {}; + + // Validate isConfigured + const configuredValidation = validateBoolean(config.isConfigured, `${provider}.isConfigured`, false); + validatedConfig.isConfigured = configuredValidation.data; + warnings.push(...configuredValidation.warnings); + + // Validate providerAuth + const authValidation = validateProviderAuth(provider, config.providerAuth); + validatedConfig.providerAuth = authValidation.data; + warnings.push(...authValidation.warnings); + + // Validate embedding models if provider supports them + if (defaultConfig.embedModels instanceof Map) { + // Validate the map of embed models + const embedModelsValidation = validateModelMap( + config.embedModels, + validateEmbedModelConfig, + defaultConfig.embedModels, + `${provider}.embedModels`, + ); + validatedConfig.embedModels = embedModelsValidation.data; + warnings.push(...embedModelsValidation.warnings); + + // Validate selected embed model + const selEmbedValidation = validateString(config.selEmbedModel, `${provider}.selEmbedModel`, false); + const selectedEmbed = selEmbedValidation.data || defaultConfig.selEmbedModel; + + if (!validatedConfig.embedModels.has(selectedEmbed)) { + warnings.push( + `Selected embed model ${selectedEmbed} not found, using default: ${defaultConfig.selEmbedModel}`, + ); + validatedConfig.selEmbedModel = defaultConfig.selEmbedModel; + } else { + validatedConfig.selEmbedModel = selectedEmbed; + } + } + + // Validate generation models if provider supports them + if (defaultConfig.genModels instanceof Map) { + // Validate the map of gen models + const genModelsValidation = validateModelMap( + config.genModels, + validateGenModelConfig, + defaultConfig.genModels, + `${provider}.genModels`, + ); + validatedConfig.genModels = genModelsValidation.data; + warnings.push(...genModelsValidation.warnings); + + // Validate selected gen model + const selGenValidation = validateString(config.selGenModel, `${provider}.selGenModel`, false); + const selectedGen = selGenValidation.data || defaultConfig.selGenModel; + + if (!validatedConfig.genModels.has(selectedGen)) { + warnings.push(`Selected gen model ${selectedGen} not found, using default: ${defaultConfig.selGenModel}`); + validatedConfig.selGenModel = defaultConfig.selGenModel; + } else { + validatedConfig.selGenModel = selectedGen; + } + } + + return { + isValid: true, + errors: [], + warnings, + data: validatedConfig as GetProviderConfig, + }; +} + +/** + * Validates the entire provider configuration + */ +function validateProviderConfigs(value: unknown): ValidationResult { + const errors: string[] = []; + const warnings: string[] = []; + const validatedConfigs: ProviderConfigs = {} as ProviderConfigs; + + if (!value || typeof value !== "object") { + warnings.push("Provider config is missing or invalid, using defaults"); + return { + isValid: true, + errors: [], + warnings, + data: DEFAULT_PROVIDER_CONFIGS, + }; + } + + const configs = value as any; + + // Validate each registered provider + for (const provider of registeredProviders) { + const validation = validateProviderConfig(provider, configs[provider]); + if (validation.isValid) { + validatedConfigs[provider] = validation.data; + warnings.push(...validation.warnings); + } else { + errors.push(...validation.errors); + warnings.push(`Using default config for ${provider} due to validation errors`); + validatedConfigs[provider] = DEFAULT_PROVIDER_CONFIGS[provider]; + } + } + + return { + isValid: true, // We can always fall back to defaults + errors, + warnings, + data: validatedConfigs as ProviderConfigs, + }; +} + +/** + * Main function to validate all plugin data + */ +export function validatePluginData(rawData: unknown): ValidationResult { + const errors: string[] = []; + const warnings: string[] = []; + const validatedData: Partial = {}; + + if (!rawData || typeof rawData !== "object") { + warnings.push("Plugin data is missing or invalid, using all defaults"); + return { + isValid: true, + errors: [], + warnings, + data: DEFAULT_SETTINGS, + }; + } + + const data = rawData as any; + + // Validate provider configuration + const providerValidation = validateProviderConfigs(data.providerConfig); + validatedData.providerConfig = providerValidation.data; + errors.push(...providerValidation.errors); + warnings.push(...providerValidation.warnings); + + // Validate provider selections + // --------------------------------------------------------------------- + // Composite selection validation (selEmbedModel / selGenModel) + // Supports new shape: + // selGenModel: { provider: RegisteredGenProvider; model: string } + // selEmbedModel: { provider: RegisteredEmbedProvider; model: string } + // Backward compatibility: + // legacy fields selGenProvider / selEmbedProvider (string) + a per-provider + // selected model stored previously (deprecated). If legacy is present and + // composite is missing or invalid we synthesize a composite. + // --------------------------------------------------------------------- + function validateCompositeSelection( + key: "selGenModel" | "selEmbedModel", + value: unknown, + defaultValue: any, + isGen: boolean, + ): { data: typeof defaultValue; warnings: string[] } { + const warnings: string[] = []; + const isObj = value && typeof value === "object" && "provider" in (value as any) && "model" in (value as any); + + if (!isObj) { + warnings.push(`${key} missing or invalid, attempting legacy fallback.`); + return { data: defaultValue, warnings }; + } + + const { provider, model } = value as any; + if (!provider || typeof provider !== "string" || !model || typeof model !== "string") { + warnings.push(`${key} has invalid provider/model fields, using default.`); + return { data: defaultValue, warnings }; + } + + if (!registeredProviders.includes(provider as any)) { + warnings.push(`${key}.provider "${provider}" not registered, using default.`); + return { data: defaultValue, warnings }; + } + + const providerCfg: any = validatedData.providerConfig?.[provider]; + if (!providerCfg) { + warnings.push(`${key}.provider "${provider}" has no config, using default.`); + return { data: defaultValue, warnings }; + } + + const map: Map | undefined = isGen ? providerCfg.genModels : providerCfg.embedModels; + if (!(map instanceof Map)) { + warnings.push(`${key}.provider "${provider}" missing model map, using default.`); + return { data: defaultValue, warnings }; + } + if (!map.has(model)) { + warnings.push(`${key}.model "${model}" not found for provider "${provider}", using default.`); + return { data: defaultValue, warnings }; + } + + return { data: { provider, model }, warnings }; + } + + // Validate composite selections (new schema) + const genSelValidation = validateCompositeSelection( + "selGenModel", + (data as any).selGenModel, + DEFAULT_SETTINGS.selGenModel, + true, + ); + validatedData.selGenModel = genSelValidation.data; + warnings.push(...genSelValidation.warnings); + + const embedSelValidation = validateCompositeSelection( + "selEmbedModel", + (data as any).selEmbedModel, + DEFAULT_SETTINGS.selEmbedModel, + false, + ); + validatedData.selEmbedModel = embedSelValidation.data; + warnings.push(...embedSelValidation.warnings); + + // Legacy fallback: if composite is still default BUT legacy provider fields exist and match a model, + // attempt to synthesize a better selection once. + if ( + ((data as any).selGenProvider || (data as any).selGenModel) && + genSelValidation.data === DEFAULT_SETTINGS.selGenModel + ) { + const legacyProv = (data as any).selGenProvider; + const legacyModel = + (data as any).selGenModel && typeof (data as any).selGenModel === "string" + ? (data as any).selGenModel + : undefined; + if ( + legacyProv && + typeof legacyProv === "string" && + registeredProviders.includes(legacyProv as any) && + legacyModel + ) { + const cfg: any = validatedData.providerConfig?.[legacyProv]; + if (cfg?.genModels instanceof Map && cfg.genModels.has(legacyModel)) { + validatedData.selGenModel = { + provider: legacyProv, + model: legacyModel, + }; + warnings.push( + `Migrated legacy selGenProvider/selGenModel to composite { provider: "${legacyProv}", model: "${legacyModel}" }.`, + ); + } + } + } + + if ( + ((data as any).selEmbedProvider || (data as any).selEmbedModel) && + embedSelValidation.data === DEFAULT_SETTINGS.selEmbedModel + ) { + const legacyProv = (data as any).selEmbedProvider; + const legacyModel = + (data as any).selEmbedModel && typeof (data as any).selEmbedModel === "string" + ? (data as any).selEmbedModel + : undefined; + if ( + legacyProv && + typeof legacyProv === "string" && + registeredProviders.includes(legacyProv as any) && + legacyModel + ) { + const cfg: any = validatedData.providerConfig?.[legacyProv]; + if (cfg?.embedModels instanceof Map && cfg.embedModels.has(legacyModel)) { + validatedData.selEmbedModel = { + provider: legacyProv, + model: legacyModel, + }; + warnings.push( + `Migrated legacy selEmbedProvider/selEmbedModel to composite { provider: "${legacyProv}", model: "${legacyModel}" }.`, + ); + } + } + } + + // Validate boolean fields + const booleanFields = [ + "isChatComfy", + "isUsingRag", + "isQuickSettingsOpen", + "isVerbose", + "isOnboarded", + "hideIncognitoWarning", + "isAutostart", + "isExcluding", + "enableLangSmith", + ] as const; + + for (const field of booleanFields) { + const validation = validateBoolean(data[field], field, DEFAULT_SETTINGS[field]); + validatedData[field] = validation.data; + warnings.push(...validation.warnings); + } + + // Validate string fields + const stringFields = [ + "initialAssistantMessageContent", + "targetFolder", + "defaultChatName", + "debuggingLangchainKey", + "langSmithApiKey", + "langSmithProject", + "langSmithEndpoint", + ] as const; + + for (const field of stringFields) { + const validation = validateString(data[field], field, false); + validatedData[field] = validation.data || DEFAULT_SETTINGS[field]; + warnings.push(...validation.warnings); + } + + // Validate number fields + const retrieveTopKValidation = validateNumber(data.retrieveTopK, "retrieveTopK", 1, 1000); + validatedData.retrieveTopK = retrieveTopKValidation.data || DEFAULT_SETTINGS.retrieveTopK; + warnings.push(...retrieveTopKValidation.warnings); + + // Validate language + const languageValidation = validateLanguage(data.assistantLanguage, "assistantLanguage"); + validatedData.assistantLanguage = languageValidation.data; + warnings.push(...languageValidation.warnings); + + // Validate string array fields + const excludeFFValidation = validateStringArray(data.excludeFF, "excludeFF"); + validatedData.excludeFF = excludeFFValidation.data || DEFAULT_SETTINGS.excludeFF; + warnings.push(...excludeFFValidation.warnings); + + const includeFFValidation = validateStringArray(data.includeFF, "includeFF"); + validatedData.includeFF = includeFFValidation.data || DEFAULT_SETTINGS.includeFF; + warnings.push(...includeFFValidation.warnings); + + // Validate defaultChatModel + if (data.defaultChatModel !== undefined && data.defaultChatModel !== null) { + const chatModel = data.defaultChatModel; + if ( + typeof chatModel === "object" && + typeof chatModel.model === "string" && + chatModel.model.length > 0 && + typeof chatModel.provider === "string" && + chatModel.provider.length > 0 + ) { + validatedData.defaultChatModel = { + model: chatModel.model, + provider: chatModel.provider, + modelConfig: chatModel.modelConfig ?? {}, + }; + } else { + warnings.push("defaultChatModel has invalid structure, using default (null)"); + validatedData.defaultChatModel = DEFAULT_SETTINGS.defaultChatModel; + } + } else { + validatedData.defaultChatModel = DEFAULT_SETTINGS.defaultChatModel; + } + + // Ensure we have all required fields + const completeData: PluginData = { + ...DEFAULT_SETTINGS, + ...validatedData, + } as PluginData; + + return { + isValid: errors.length === 0, + errors, + warnings, + data: completeData, + }; +} + +/** + * Type guard to check if data is valid PluginData + */ +export function isValidPluginData(data: unknown): data is PluginData { + const validation = validatePluginData(data); + return validation.isValid; +} + +/** + * Safely load and validate plugin data + */ +export function safeLoadPluginData(rawData: unknown): { + data: PluginData; + hasErrors: boolean; + hasWarnings: boolean; + errors: string[]; + warnings: string[]; +} { + const validation = validatePluginData(rawData); + + return { + data: validation.data as PluginData, + hasErrors: validation.errors.length > 0, + hasWarnings: validation.warnings.length > 0, + errors: validation.errors, + warnings: validation.warnings, + }; +} diff --git a/src/utils/markdownHelper.ts b/src/utils/markdownHelper.ts new file mode 100644 index 00000000..212ddf31 --- /dev/null +++ b/src/utils/markdownHelper.ts @@ -0,0 +1,138 @@ +import { + MarkdownRenderer, + Keymap, + loadMathJax, + type App, + type Component, +} from "obsidian"; + +type RenderOptions = { + app: App; + content: string; + container: HTMLElement; + sourcePath: string; + component: Component; + enableMath?: boolean; // default true +}; + +export function createMarkdownRenderer({ + app, + container, + sourcePath, + component, + enableMath = true, + content, +}: RenderOptions) { + let raf = 0; + + const render = async (markdown: string) => { + if (enableMath) await loadMathJax(); + + container.innerHTML = ""; + await MarkdownRenderer.render( + app, + markdown ?? "", + container, + sourcePath, + component, + ); + + // Copy button styling + const copyBtn = container.querySelector( + ".copy-code-button", + ) as HTMLElement | null; + if (copyBtn) { + copyBtn.className = "clickable-icon"; + copyBtn.setAttribute("aria-label", "Copy code"); + } + + // Link helpers + const getLinkText = (link: HTMLAnchorElement): string | null => + link.getAttribute("href") || link.getAttribute("data-href"); + + const clickHandler = (evt: Event) => { + const target = evt.target as HTMLElement; + const link = target.closest( + "a.internal-link", + ) as HTMLAnchorElement | null; + if (!link) return; + const mouseEvent = evt as MouseEvent; + mouseEvent.preventDefault(); + mouseEvent.stopPropagation(); + const linktext = getLinkText(link); + if (linktext) { + app.workspace.openLinkText( + linktext, + sourcePath, + Keymap.isModEvent(mouseEvent), + ); + } + }; + + const hoverHandler = (evt: Event) => { + const target = evt.target as HTMLElement; + const link = target.closest( + "a.internal-link", + ) as HTMLAnchorElement | null; + if (!link) return; + const mouseEvent = evt as MouseEvent; + const linktext = getLinkText(link); + if (linktext) { + app.workspace.trigger("hover-link", { + event: mouseEvent, + source: "preview", + hoverParent: { hoverPopover: null }, + targetEl: mouseEvent.currentTarget, + linktext, + sourcePath, + }); + } + }; + + container.addEventListener("click", clickHandler, true); + container.addEventListener("mouseover", hoverHandler, true); + + // Normalize internal links + container.querySelectorAll("a.internal-link").forEach((a) => { + const link = a as HTMLAnchorElement; + link.removeAttribute("target"); + link.removeAttribute("rel"); + link.style.cursor = "pointer"; + }); + + // External links: open in new tab safely + container.querySelectorAll("a:not(.internal-link)").forEach((a) => { + const link = a as HTMLAnchorElement; + link.target = "_blank"; + link.rel = "noopener"; + }); + + // Return a cleanup that removes listeners for this render pass + return () => { + container.removeEventListener("click", clickHandler, true); + container.removeEventListener("mouseover", hoverHandler, true); + }; + }; + + // Initial render + cleanup handle + let cleanup = Promise.resolve<() => void>(() => {}); + + (async () => { + cleanup = Promise.resolve(await render(content)); + })(); + + return { + update(next: string) { + cancelAnimationFrame(raf); + raf = requestAnimationFrame(async () => { + (await cleanup)(); // remove old listeners + cleanup = Promise.resolve(await render(next)); + }); + }, + async destroy() { + cancelAnimationFrame(raf); + (await cleanup)(); + container.innerHTML = ""; + }, + }; +} diff --git a/src/utils/obsidianFetch.ts b/src/utils/obsidianFetch.ts new file mode 100644 index 00000000..116f4ce6 --- /dev/null +++ b/src/utils/obsidianFetch.ts @@ -0,0 +1,115 @@ +import { requestUrl, type RequestUrlParam } from "obsidian"; + +/** + * Creates a custom fetch implementation that uses Obsidian's requestUrl + * to bypass CORS restrictions in the plugin environment. + */ +export function createObsidianFetch(originalFetch?: (input: RequestInfo | URL, init?: RequestInit) => Promise): (input: RequestInfo | URL, init?: RequestInit) => Promise { + return async (input: RequestInfo | URL, init?: RequestInit): Promise => { + // Try using the original fetch first to support streaming + if (originalFetch) { + try { + // We clone the init object to avoid side effects if fetch modifies it, + // though usually it doesn't. + // NOTE: If body is a ReadableStream and it gets locked/consumed by originalFetch, + // fallback to requestUrl might fail. But usually for LLM calls body is a string (JSON). + return await originalFetch(input, init); + } catch (e) { + // If original fetch fails (likely CORS or network), fallback to requestUrl + } + } + + const url = input.toString(); + const method = init?.method || "GET"; + const headers = init?.headers as Record || {}; + const body = init?.body as string; + + // Convert Headers object to record if needed + if (init?.headers instanceof Headers) { + init.headers.forEach((value, key) => { + headers[key] = value; + }); + } + + // If the body is a byte array (Uint8Array), requestUrl expects it as an ArrayBuffer + // However, for multipart/form-data or gzipped content, we might need special handling + + let requestBody = body; + // Check if body exists and is NOT a string (so it's likely binary) + if (init?.body && typeof init.body !== 'string') { + // Handle Uint8Array specifically (common in node/browser buffers) + if (init.body instanceof Uint8Array) { + // If it's a view on a larger buffer, we need to slice it + if (init.body.byteLength !== init.body.buffer.byteLength) { + requestBody = init.body.buffer.slice(init.body.byteOffset, init.body.byteOffset + init.body.byteLength) as any; + } else { + requestBody = init.body.buffer as any; + } + } + // Handle generic ArrayBufferView + else if (ArrayBuffer.isView(init.body)) { + requestBody = init.body.buffer as any; + } + // Handle raw ArrayBuffer + else if (init.body instanceof ArrayBuffer) { + requestBody = init.body as any; + } + // Handle Blob + else if (init.body instanceof Blob) { + requestBody = await init.body.arrayBuffer() as any; + } + // Handle ReadableStream + else if (init.body instanceof ReadableStream) { + // We need to read the stream into an ArrayBuffer + const reader = init.body.getReader(); + const chunks = []; + let totalLength = 0; + + while (true) { + const { done, value } = await reader.read(); + if (done) break; + chunks.push(value); + totalLength += value.length; + } + + // Merge chunks into a single Uint8Array + const result = new Uint8Array(totalLength); + let offset = 0; + for (const chunk of chunks) { + result.set(chunk, offset); + offset += chunk.length; + } + + requestBody = result.buffer as any; + } + } + + // CRITICAL: requestUrl in Obsidian often tries to set Content-Type automatically + // If we are sending binary data (like gzip), we must ensure we don't double-encode or mess up headers. + + // LangSmith/LangChain sends 'Content-Encoding: gzip' header. + // Ensure we are passing the raw buffer. + + const requestParams: RequestUrlParam = { + url, + method, + headers, + body: requestBody, + throw: false // Don't throw on 4xx/5xx to match fetch behavior + }; + + try { + const response = await requestUrl(requestParams); + + // Convert Obsidian response to standard Response object + return new Response(response.text, { + status: response.status, + headers: response.headers as Record + }); + } catch (error) { + console.error("Obsidian fetch proxy error:", error); + throw error; + } + }; +} + diff --git a/src/utils/query.ts b/src/utils/query.ts new file mode 100644 index 00000000..17cd64a8 --- /dev/null +++ b/src/utils/query.ts @@ -0,0 +1,53 @@ +import { createQuery } from "@tanstack/svelte-query"; +import { QueryClient } from "@tanstack/svelte-query"; +import type { RegisteredProvider } from "../types/providers"; +import { getPlugin } from "../stores/state.svelte"; +import { getData } from "../stores/dataStore.svelte"; +import type { ValidationResult } from "../agent/AgentManager"; + +// Create a global QueryClient instance +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + staleTime: 1000 * 60 * 5, // 5 minutes + gcTime: 1000 * 60 * 10, // 10 minutes + retry: false, + refetchOnWindowFocus: false, + }, + }, +}); + +export function getQueryClient() { + return queryClient; +} + +export function createAuthStateQuery(provider: () => RegisteredProvider) { + const plugin = getPlugin(); + const data = getData(); + + return createQuery(() => ({ + queryKey: ["authState", provider()], + queryFn: async () => { + const res = await plugin.agentManager.testProviderConfig( + provider(), + data.getProviderAuthParams(provider()), + ); + return res; + }, + })); +} + +export function invalidateAuthState(provider: RegisteredProvider) { + const plugin = getPlugin(); + plugin.queryClient.invalidateQueries({ + queryKey: ["authState", provider], + }); +} + +export function createModelListQuery(provider: () => RegisteredProvider) { + const plugin = getPlugin(); + return createQuery(() => ({ + queryKey: ["models", provider()], + queryFn: async () => plugin.agentManager.getAvailableModels(provider()), + })); +} diff --git a/src/utils/threadId.ts b/src/utils/threadId.ts new file mode 100644 index 00000000..06d70dfe --- /dev/null +++ b/src/utils/threadId.ts @@ -0,0 +1,12 @@ +import { getData } from "../stores/dataStore.svelte"; + +export function createThreadId(): string { + const now = new Date(); + const year = now.getFullYear(); + const month = String(now.getMonth() + 1).padStart(2, "0"); + const day = String(now.getDate()).padStart(2, "0"); + const hours = String(now.getHours()).padStart(2, "0"); + const minutes = String(now.getMinutes()).padStart(2, "0"); + const seconds = String(now.getSeconds()).padStart(2, "0"); + return `${getData().defaultChatName} ${year}-${month}-${day} ${hours}-${minutes}-${seconds}`; +} diff --git a/src/utils/utils.ts b/src/utils/utils.ts new file mode 100644 index 00000000..326faefd --- /dev/null +++ b/src/utils/utils.ts @@ -0,0 +1,15 @@ +import { MarkdownRenderer, setIcon } from "obsidian"; +import { getPlugin } from "../stores/state.svelte"; + +export const icon = (node: HTMLElement, iconId: string) => { + setIcon(node, iconId); +}; + +export function wildTest(wildcard: string, str: string): boolean { + const w = wildcard.replace(/[.+^${}()|[\]\\]/g, "\\$&"); // regexp escape + const re = new RegExp( + `\\b${w.replace(/\*/g, ".*").replace(/\?/g, ".")}`, + "i", + ); + return re.test(str); +} diff --git a/src/utils/uuid7Validator.ts b/src/utils/uuid7Validator.ts new file mode 100644 index 00000000..3d00e1b0 --- /dev/null +++ b/src/utils/uuid7Validator.ts @@ -0,0 +1,27 @@ +import { v7 as uuidv7, validate, version } from "uuid"; + +declare const brand: unique symbol; +export type UUIDv7 = string & { readonly [brand]: "uuidv7" }; + +// Generate a branded UUIDv7 +export function genUUIDv7(): UUIDv7 { + return uuidv7() as UUIDv7; +} + +// Type guard +export function isUUIDv7(s: string): s is UUIDv7 { + return validate(s) && version(s) === 7; +} + +// Parse Date from a UUIDv7 (first 48 bits are Unix epoch ms) +export function dateFromUUIDv7(id: UUIDv7): Date { + const hex = id.replace(/-/g, "").slice(0, 12); // 48 bits (12 hex chars) + const ms = parseInt(hex, 16); + return new Date(ms); +} + +// Unsafe cast with runtime validation (throws on mismatch) +export function asUUIDv7(s: string): UUIDv7 { + if (!isUUIDv7(s)) throw new Error(`Not a UUIDv7: ${s}`); + return s; +} diff --git a/src/utils/wikiLinkExtraction.ts b/src/utils/wikiLinkExtraction.ts new file mode 100644 index 00000000..647ce31c --- /dev/null +++ b/src/utils/wikiLinkExtraction.ts @@ -0,0 +1,56 @@ +export interface WikiLinkContext { + fullStart: number; + fullEnd: number; + innerStart: number; + innerEnd: number; + inner: string; + filePart: string; + displayPart: string | null; +} + +/** + * Returns context if the cursor is inside [[...]]. + * cursor: position (selectionStart) inside the text. + */ +export function getWikiLinkAtCursor( + text: string, + cursor: number, +): WikiLinkContext | null { + // Slice before cursor and find the nearest opening [[ + const before = text.slice(0, cursor); + const open = before.lastIndexOf("[["); + if (open === -1) return null; + + // Ensure there is not a closing ]] after that open but still before cursor (would mean you're outside) + const lastCloseBefore = before.lastIndexOf("]]"); + if (lastCloseBefore > open) return null; // We are after a closed link. + + // Now look forward from cursor for the closing ]] + const after = text.slice(cursor); + const relativeClose = after.indexOf("]]"); + if (relativeClose === -1) return null; // Not closed yet. + + const fullStart = open; + const fullEnd = cursor + relativeClose + 2; // +2 for length of ]] + const innerStart = fullStart + 2; + const innerEnd = fullEnd - 2; + if (cursor < innerStart || cursor > innerEnd) return null; + + const inner = text.slice(innerStart, innerEnd); + if (inner.includes("\n")) return null; + + // Extract file|alias + const pipeIdx = inner.indexOf("|"); + const filePart = pipeIdx === -1 ? inner : inner.slice(0, pipeIdx); + const displayPart = pipeIdx === -1 ? null : inner.slice(pipeIdx + 1); + + return { + fullStart, + fullEnd, + innerStart, + innerEnd, + inner, + filePart, + displayPart, + }; +} diff --git a/src/views/Chat/Chat.svelte b/src/views/Chat/Chat.svelte new file mode 100755 index 00000000..3cd06025 --- /dev/null +++ b/src/views/Chat/Chat.svelte @@ -0,0 +1,25 @@ + + + +
+ + isInputFocused = focused} onMessageSent={() => messageContainer.scrollToLatestMessage()} /> +
+
diff --git a/src/views/Chat/Chat.ts b/src/views/Chat/Chat.ts new file mode 100755 index 00000000..44ac10fd --- /dev/null +++ b/src/views/Chat/Chat.ts @@ -0,0 +1,50 @@ +import { FileView, TFile, WorkspaceLeaf } from "obsidian"; +import ChatViewComponent from "./Chat.svelte"; +import { mount, unmount } from "svelte"; +import type SecondBrainPlugin from "../../main"; +import { getMessenger } from "../../stores/chatStore.svelte"; + +export const VIEW_TYPE_CHAT = "smart-second-brain-chat"; + +export class ChatView extends FileView { + plugin!: SecondBrainPlugin; + component!: ChatViewComponent; + + // Keep constructor signature stable for current registrations + constructor(leaf: WorkspaceLeaf, plugin: SecondBrainPlugin) { + super(leaf); + this.plugin = plugin; + } + + getViewType() { + return VIEW_TYPE_CHAT; + } + + getDisplayText() { + if (this.file) return this.file.basename; + return "Smart Second Brain"; + } + + getIcon() { + return "message-square"; + } + + async onLoadFile(file: TFile): Promise { + await super.onLoadFile(file); + const messenger = getMessenger(); + messenger?.loadSession(file); + } + + protected async onOpen(): Promise { + this.component = mount(ChatViewComponent, { + target: this.contentEl, + props: {}, + }); + return super.onOpen(); + } + + async onClose() { + super.onClose(); + if (this.component) unmount(this.component); + } +} diff --git a/src/views/ChatModelManagement/ChatModelManagement.svelte b/src/views/ChatModelManagement/ChatModelManagement.svelte new file mode 100644 index 00000000..e1b3e656 --- /dev/null +++ b/src/views/ChatModelManagement/ChatModelManagement.svelte @@ -0,0 +1,165 @@ + + + + diff --git a/src/views/ChatModelManagement/ChatModelManagement.ts b/src/views/ChatModelManagement/ChatModelManagement.ts new file mode 100644 index 00000000..7567c0ed --- /dev/null +++ b/src/views/ChatModelManagement/ChatModelManagement.ts @@ -0,0 +1,53 @@ +import { App, Modal } from "obsidian"; +import type { GenModelConfig } from "papa-ts"; +import { mount } from "svelte"; +import type SecondBrainPlugin from "../../main"; +import ModalProvider from "../../components/QueryClientProvider.svelte"; +import ChatModelManagementComponent from "./ChatModelManagement.svelte"; +import type { GenProviders } from "../../types/providers"; + +export class ChatModelManagementModal extends Modal { + private component!: ChatModelManagementComponent; + private plugin: SecondBrainPlugin; + private provider!: GenProviders; + private config?: GenModelConfig; + + constructor( + plugin: SecondBrainPlugin, + provider: GenProviders, + config?: GenModelConfig, + ) { + super(plugin.app); + this.plugin = plugin; + this.setTitle(`${provider} Chat Model Management`); + this.provider = provider; + this.config = config; + } + + onOpen() { + this.component = mount( + ModalProvider<{ + modal: ChatModelManagementModal; + provider: GenProviders; + config?: GenModelConfig; + }>, + { + target: this.contentEl, + props: { + plugin: this.plugin, + component: ChatModelManagementComponent, + componentProps: { + modal: this, + provider: this.provider, + config: this.config, + }, + }, + }, + ); + } + + onClose() { + const { contentEl } = this; + contentEl.empty(); + } +} diff --git a/src/views/EmbedModelManagement/EmbedModelManagement.svelte b/src/views/EmbedModelManagement/EmbedModelManagement.svelte new file mode 100644 index 00000000..652a2a16 --- /dev/null +++ b/src/views/EmbedModelManagement/EmbedModelManagement.svelte @@ -0,0 +1,141 @@ + + + + + diff --git a/src/views/EmbedModelManagement/EmbedModelManagement.ts b/src/views/EmbedModelManagement/EmbedModelManagement.ts new file mode 100644 index 00000000..1d8c85d1 --- /dev/null +++ b/src/views/EmbedModelManagement/EmbedModelManagement.ts @@ -0,0 +1,53 @@ +import { App, Modal } from "obsidian"; +import type { EmbedModelConfig } from "papa-ts"; +import { mount } from "svelte"; +import type SecondBrainPlugin from "../../main"; +import ModalProvider from "../../components/QueryClientProvider.svelte"; +import EmbedModelManagementComponent from "./EmbedModelManagement.svelte"; +import type { EmbedProviders } from "../../types/providers"; + +export class EmbedModelManagementModal extends Modal { + private component!: EmbedModelManagementComponent; + private plugin: SecondBrainPlugin; + private provider!: EmbedProviders; + private config?: EmbedModelConfig; + + constructor( + plugin: SecondBrainPlugin, + provider: EmbedProviders, + config?: EmbedModelConfig, + ) { + super(plugin.app); + this.plugin = plugin; + this.setTitle(`${provider} Embed Model Management`); + this.provider = provider; + this.config = config; + } + + onOpen() { + this.component = mount( + ModalProvider<{ + modal: EmbedModelManagementModal; + provider: EmbedProviders; + config?: EmbedModelConfig; + }>, + { + target: this.contentEl, + props: { + plugin: this.plugin, + component: EmbedModelManagementComponent, + componentProps: { + modal: this, + provider: this.provider, + config: this.config, + }, + }, + }, + ); + } + + onClose() { + const { contentEl } = this; + contentEl.empty(); + } +} diff --git a/src/views/ProviderSetup/ProviderSetup.svelte b/src/views/ProviderSetup/ProviderSetup.svelte new file mode 100644 index 00000000..91db50f0 --- /dev/null +++ b/src/views/ProviderSetup/ProviderSetup.svelte @@ -0,0 +1,118 @@ + + + + + diff --git a/src/views/ProviderSetup/ProviderSetup.ts b/src/views/ProviderSetup/ProviderSetup.ts new file mode 100644 index 00000000..693837b3 --- /dev/null +++ b/src/views/ProviderSetup/ProviderSetup.ts @@ -0,0 +1,49 @@ +import { App, Modal } from "obsidian"; +import ProviderSetupComponent from "./ProviderSetup.svelte"; +import ModalProvider from "../../components/QueryClientProvider.svelte"; +import { mount } from "svelte"; +import type { RegisteredProvider } from "../../types/providers"; +import type SecondBrainPlugin from "../../main"; + +export class ProviderSetupModal extends Modal { + component!: ProviderSetupComponent; + plugin: SecondBrainPlugin; + selectedProvider: RegisteredProvider; + + constructor(plugin: SecondBrainPlugin, selectedProvider: RegisteredProvider) { + super(plugin.app); + this.plugin = plugin; + this.setTitle(`Setup ${selectedProvider}`); + this.selectedProvider = selectedProvider; + } + + onOpen() { + this.component = mount( + ModalProvider<{ + modal: ProviderSetupModal; + plugin: SecondBrainPlugin; + selectedProvider: RegisteredProvider; + }>, + { + target: this.contentEl, + props: { + plugin: this.plugin, + component: ProviderSetupComponent, + componentProps: { + modal: this, + plugin: this.plugin, + selectedProvider: this.selectedProvider, + }, + }, + }, + ); + } + + onClose() { + const { contentEl } = this; + contentEl.empty(); + } +} + +// Export for backwards compatibility +export const ProviderSetup = ProviderSetupModal; diff --git a/src/views/Settings/Settings.svelte b/src/views/Settings/Settings.svelte new file mode 100755 index 00000000..4f87ac67 --- /dev/null +++ b/src/views/Settings/Settings.svelte @@ -0,0 +1,203 @@ + + + + +Chat Settings + + + suggestFolders().filter((f) => + f.path.toLowerCase().includes(q.toLowerCase()), + )} + onSelected={(path: string) => (pluginData.targetFolder = path)} + onSubmit={(path: string) => (pluginData.targetFolder = path)} + /> + + + + (pluginData.defaultChatName = value)} + /> + + + + pluginData.toggleGeneratingChatTitle()} + /> + + + + + + +RAG Config + + + pluginData.toggleAutostart()} + /> + + + + + + fuzzySuggestModel.open()} + buttonText={"Manage"} + /> + + + + + console.log("Not set up")} + /> + + +
+ + + { + console.log("Delete Plugin Data"); + }} + /> + + + + + + (pluginData.enableLangSmith = !pluginData.enableLangSmith)} + /> + + {#if pluginData.enableLangSmith} + + (pluginData.langSmithApiKey = v)} + /> + + + (pluginData.langSmithProject = v)} + /> + + + (pluginData.langSmithEndpoint = v)} + /> + + {/if} + + + + + console.log("Change verbose")} + /> + +
diff --git a/src/views/Settings/Settings.ts b/src/views/Settings/Settings.ts new file mode 100755 index 00000000..65140be1 --- /dev/null +++ b/src/views/Settings/Settings.ts @@ -0,0 +1,41 @@ +import { PluginSettingTab } from "obsidian"; +import SecondBrainPlugin from "../../main"; +import SettingsComponent from "./Settings.svelte"; +import { mount } from "svelte"; +import QueryClientProvider from "../../components/QueryClientProvider.svelte"; + +export default class SettingsTab extends PluginSettingTab { + // keep a handle so we can destroy it on hide() + instance: ReturnType | null = null; + plugin: SecondBrainPlugin; + + constructor(plugin: SecondBrainPlugin) { + super(plugin.app, plugin); + this.plugin = plugin; + } + + display(): void { + this.containerEl.empty(); + + // Destroy any previous instance to avoid leaks (if display is called again) + this.instance?.destroy?.(); + + this.instance = mount(QueryClientProvider, { + target: this.containerEl, + props: { + plugin: this.plugin, + component: SettingsComponent, + componentProps: { + plugin: this.plugin, + }, + }, + }); + } + + hide(): void { + // Clean up when leaving the settings tab + this.instance?.destroy?.(); + this.instance = null; + this.containerEl.empty(); + } +} diff --git a/svelte.config.ts b/svelte.config.ts index 692e6140..3579818f 100644 --- a/svelte.config.ts +++ b/svelte.config.ts @@ -1,13 +1,12 @@ -import type { RollupWarning } from 'rollup'; +import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"; -const config = { - onwarn: (warning: RollupWarning, handler: (warning: RollupWarning) => void) => { - const { code, frame } = warning; - if (code?.startsWith('a11y-')) return; - - // let Rollup handle all other warnings normally - handler(warning); - }, +export default { + preprocess: vitePreprocess(), + compilerOptions: { + runes: true, + }, + onwarn: (warning, handler) => { + if (warning.code && warning.code.startsWith("a11y")) return; + handler(warning); + }, }; - -export default config; diff --git a/tailwind.config.js b/tailwind.config.js index 837ebe7d..ad393b78 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,39 +1,237 @@ /** @type {import('tailwindcss').Config} */ export default { - content: ['./src/**/*.{js,svelte,ts}'], - theme: { - extend: { - colors: { - primary: { - DEFAULT: 'var(--color-accent)', - }, - secondary: { - DEFAULT: 'hsl(var(--accent-h), 10%, var(--accent-l))', - }, - slate: { - 0o0: 'var(--color-base-00)', - 0o5: 'var(--color-base-05)', - 10: 'var(--color-base-10)', - 20: 'var(--color-base-20)', - 25: 'var(--color-base-25)', - 30: 'var(--color-base-30)', - 35: 'var(--color-base-35)', - 40: 'var(--color-base-40)', - 50: 'var(--color-base-50)', - 60: 'var(--color-base-60)', - 70: 'var(--color-base-70)', - 100: 'var(--color-base-100)', - }, - }, - }, - }, - variants: { - extend: { - display: ['group-hover'], - }, - }, - corePlugins: { - preflight: false, - }, - plugins: [], + content: ["./src/**/*.{js,svelte,ts}", "./v2/**/*.{js,svelte,ts}"], + theme: { + extend: { + colors: { + // === Obsidian Accent Colors === + accent: { + DEFAULT: "var(--color-accent)", + h: "var(--accent-h)", + s: "var(--accent-s)", + l: "var(--accent-l)", + }, + + // === Obsidian Base Colors (neutral palette) === + base: { + "00": "var(--color-base-00)", + "05": "var(--color-base-05)", + 10: "var(--color-base-10)", + 20: "var(--color-base-20)", + 25: "var(--color-base-25)", + 30: "var(--color-base-30)", + 35: "var(--color-base-35)", + 40: "var(--color-base-40)", + 50: "var(--color-base-50)", + 60: "var(--color-base-60)", + 70: "var(--color-base-70)", + 100: "var(--color-base-100)", + }, + + // === Obsidian Extended Colors === + ob: { + red: "var(--color-red)", + orange: "var(--color-orange)", + yellow: "var(--color-yellow)", + green: "var(--color-green)", + cyan: "var(--color-cyan)", + blue: "var(--color-blue)", + purple: "var(--color-purple)", + pink: "var(--color-pink)", + }, + + // === Obsidian Background/Surface Colors === + background: { + primary: "var(--background-primary)", + "primary-alt": "var(--background-primary-alt)", + secondary: "var(--background-secondary)", + "secondary-alt": "var(--background-secondary-alt)", + }, + + // === Obsidian Background Modifiers === + "bg-modifier": { + hover: "var(--background-modifier-hover)", + "active-hover": "var(--background-modifier-active-hover)", + border: "var(--background-modifier-border)", + "border-hover": "var(--background-modifier-border-hover)", + "border-focus": "var(--background-modifier-border-focus)", + error: "var(--background-modifier-error)", + "error-hover": "var(--background-modifier-error-hover)", + success: "var(--background-modifier-success)", + message: "var(--background-modifier-message)", + "form-field": "var(--background-modifier-form-field)", + }, + + // === Obsidian Interactive Colors === + interactive: { + normal: "var(--interactive-normal)", + hover: "var(--interactive-hover)", + accent: "var(--interactive-accent)", + "accent-hover": "var(--interactive-accent-hover)", + }, + + // === Obsidian Text Colors === + text: { + normal: "var(--text-normal)", + muted: "var(--text-muted)", + faint: "var(--text-faint)", + "on-accent": "var(--text-on-accent)", + "on-accent-inverted": "var(--text-on-accent-inverted)", + success: "var(--text-success)", + warning: "var(--text-warning)", + error: "var(--text-error)", + accent: "var(--text-accent)", + "accent-hover": "var(--text-accent-hover)", + selection: "var(--text-selection)", + "highlight-bg": "var(--text-highlight-bg)", + }, + + // === Obsidian Code Colors === + code: { + background: "var(--code-background)", + normal: "var(--code-normal)", + comment: "var(--code-comment)", + function: "var(--code-function)", + important: "var(--code-important)", + keyword: "var(--code-keyword)", + operator: "var(--code-operator)", + property: "var(--code-property)", + punctuation: "var(--code-punctuation)", + string: "var(--code-string)", + tag: "var(--code-tag)", + value: "var(--code-value)", + }, + + // === Obsidian Icon Colors === + icon: { + DEFAULT: "var(--icon-color)", + hover: "var(--icon-color-hover)", + active: "var(--icon-color-active)", + focused: "var(--icon-color-focused)", + }, + }, + + // === Obsidian Spacing (4px grid) === + spacing: { + // 2px grid (use sparingly) + "size-2-1": "var(--size-2-1)", + "size-2-2": "var(--size-2-2)", + "size-2-3": "var(--size-2-3)", + // 4px grid (primary) + "size-4-1": "var(--size-4-1)", + "size-4-2": "var(--size-4-2)", + "size-4-3": "var(--size-4-3)", + "size-4-4": "var(--size-4-4)", + "size-4-5": "var(--size-4-5)", + "size-4-6": "var(--size-4-6)", + "size-4-8": "var(--size-4-8)", + "size-4-9": "var(--size-4-9)", + "size-4-12": "var(--size-4-12)", + "size-4-16": "var(--size-4-16)", + "size-4-18": "var(--size-4-18)", + // Icon sizes + "icon-xs": "var(--icon-xs)", + "icon-s": "var(--icon-s)", + "icon-m": "var(--icon-m)", + "icon-l": "var(--icon-l)", + "icon-xl": "var(--icon-xl)", + }, + + // === Obsidian Border Radius === + borderRadius: { + "radius-s": "var(--radius-s)", + "radius-m": "var(--radius-m)", + "radius-l": "var(--radius-l)", + "radius-xl": "var(--radius-xl)", + "clickable-icon": "var(--clickable-icon-radius)", + }, + + // === Obsidian Font Sizes === + fontSize: { + // Relative (for editor) + "font-smallest": "var(--font-smallest)", + "font-smaller": "var(--font-smaller)", + "font-small": "var(--font-small)", + "font-text": "var(--font-text-size)", + // Fixed (for UI) + "ui-smaller": "var(--font-ui-smaller)", + "ui-small": "var(--font-ui-small)", + "ui-medium": "var(--font-ui-medium)", + "ui-large": "var(--font-ui-large)", + // Icon sizes (for icon font-size) + "icon-xs": "var(--icon-xs)", + "icon-s": "var(--icon-s)", + "icon-m": "var(--icon-m)", + "icon-l": "var(--icon-l)", + "icon-xl": "var(--icon-xl)", + }, + + // === Obsidian Font Weights === + fontWeight: { + "ob-thin": "var(--font-thin)", + "ob-extralight": "var(--font-extralight)", + "ob-light": "var(--font-light)", + "ob-normal": "var(--font-normal)", + "ob-medium": "var(--font-medium)", + "ob-semibold": "var(--font-semibold)", + "ob-bold": "var(--font-bold)", + "ob-extrabold": "var(--font-extrabold)", + "ob-black": "var(--font-black)", + }, + + // === Obsidian Font Family === + fontFamily: { + interface: "var(--font-interface-theme)", + text: "var(--font-text-theme)", + mono: "var(--font-monospace-theme)", + }, + + // === Obsidian Line Heights === + lineHeight: { + "ob-normal": "var(--line-height-normal)", + "ob-tight": "var(--line-height-tight)", + }, + + // === Obsidian Opacity === + opacity: { + icon: "var(--icon-opacity)", + "icon-hover": "var(--icon-opacity-hover)", + "icon-active": "var(--icon-opacity-active)", + }, + + // === Obsidian Stroke Width (for icons) === + strokeWidth: { + "icon-xs": "var(--icon-xs-stroke-width)", + "icon-s": "var(--icon-s-stroke-width)", + "icon-m": "var(--icon-m-stroke-width)", + "icon-l": "var(--icon-l-stroke-width)", + "icon-xl": "var(--icon-xl-stroke-width)", + }, + + // === Animations === + keyframes: { + "accordion-down": { + from: { height: "0" }, + to: { height: "var(--bits-accordion-content-height)" }, + }, + "accordion-up": { + from: { height: "var(--bits-accordion-content-height)" }, + to: { height: "0" }, + }, + }, + animation: { + "accordion-down": "accordion-down 200ms ease-out", + "accordion-up": "accordion-up 200ms ease-in", + }, + }, + }, + variants: { + extend: { + display: ["group-hover"], + }, + }, + corePlugins: { + preflight: false, + }, + plugins: [], }; diff --git a/tsconfig.json b/tsconfig.json index 8365c43c..222fdfe8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,21 +1,37 @@ { - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ES6", - "resolveJsonModule": true, - "allowJs": true, - "isolatedModules": true, - "noEmitOnError": true, - "plugins": [ - { - "name": "typescript-svelte-plugin", - // the following options can be set additionally; they are optional; their default values are listed here - "enabled": true, // enables this plugin - "assumeIsSvelteProject": true // if true, skip detection and always assume it's a Svelte project - } - ] - }, - "include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.js", "src/**/*.svelte"] + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "allowJs": true, + "isolatedModules": true, + "noEmitOnError": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "skipLibCheck": true, + "strict": true, + "types": ["svelte", "vite/client"], + "plugins": [ + { + "name": "typescript-svelte-plugin", + "enabled": true, + "assumeIsSvelteProject": true, + }, + ], + }, + "watchOptions": { + "watchFile": "useFsEvents", + "watchDirectory": "useFsEvents", + }, + "include": [ + "src/**/*.d.ts", + "src/**/*.ts", + "src/**/*.js", + "src/**/*.svelte", + "v2/src/**/*.ts", + "v2/src/**/*.svelte", + ], } diff --git a/versions.json b/versions.json index 4e32a57e..e5ac8618 100644 --- a/versions.json +++ b/versions.json @@ -1,23 +1,19 @@ { - "0.1.2": "1.5.0" - "0.1.3": "1.5.0" - "0.1.4": "1.5.0" - "0.2.0": "1.5.0" - "0.2.1": "1.5.0" - "0.2.2": "1.5.0" - "0.2.3": "1.5.0" - "0.2.4": "1.5.0" - "0.2.5": "1.5.0" - "0.2.6": "1.5.0" - "0.2.7": "1.5.0" - "0.2.8": "1.5.0" - "0.4.0": "1.5.0" - "0.5.0": "1.5.0" - "0.6.0": "1.5.0" + "0.1.2": "1.5.0", + "0.1.3": "1.5.0", + "0.1.4": "1.5.0", + "0.2.0": "1.5.0", + "0.2.1": "1.5.0", + "0.2.2": "1.5.0", + "0.2.3": "1.5.0", + "0.2.4": "1.5.0", + "0.2.5": "1.5.0", + "0.2.6": "1.5.0", + "0.2.7": "1.5.0", + "0.2.8": "1.5.0", + "0.4.0": "1.5.0", + "0.5.0": "1.5.0", + "0.6.0": "1.5.0", "1.0.0": "1.5.0" - "1.0.2": "1.5.0" - "1.1.0": "1.5.0" - "1.1.1": "1.5.0" - "1.2.0": "1.5.0" - "1.3.0": "1.5.0" } + diff --git a/vite.config.ts b/vite.config.ts index 26a14cb4..0c2c5352 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,56 +1,72 @@ -import { svelte, vitePreprocess } from '@sveltejs/vite-plugin-svelte'; -import builtins from 'builtin-modules'; -import { defineConfig } from 'vite'; -import { pathToFileURL } from 'url'; -import typescript from '@rollup/plugin-typescript'; +// vite.config.ts +import { svelte, vitePreprocess } from "@sveltejs/vite-plugin-svelte"; +import { defineConfig } from "vite"; + +import builtinModules from "builtin-modules"; const setOutDir = (mode: string) => { - switch (mode) { - case 'development': - return './build/smart-second-brain/'; - case 'production': - return 'build/prod'; - } + switch (mode) { + case "development": + return "./build/smart-second-brain/"; + case "production": + return "./build/prod"; + default: + console.warn(`Unexpected mode: "${mode}". Defaulting to development output directory.`); + return "./build/smart-second-brain/"; + } }; export default defineConfig(({ mode }) => { - return { - plugins: [svelte({ preprocess: vitePreprocess() })], - build: { - lib: { - entry: 'src/main', - formats: ['cjs'], - }, - rollupOptions: { - plugins: [typescript({ tsconfig: './tsconfig.json' })], - output: { - entryFileNames: 'main.js', - assetFileNames: 'styles.css', - sourcemapBaseUrl: pathToFileURL(`${__dirname}/build/smart-second-brain/`).toString(), - }, - external: [ - 'obsidian', - 'electron', - '@codemirror/autocomplete', - '@codemirror/collab', - '@codemirror/commands', - '@codemirror/language', - '@codemirror/lint', - '@codemirror/search', - '@codemirror/state', - '@codemirror/view', - '@lezer/common', - '@lezer/highlight', - '@lezer/lr', - ...builtins, - ], - }, - outDir: setOutDir(mode), - emptyOutDir: false, - sourcemap: true, - }, - css: { - devSourcemap: true, - }, - }; + const isDevelopment = mode === "development"; + + return { + plugins: [ + svelte({ + preprocess: vitePreprocess(), + onwarn: (warning, handler) => { + if (warning.code && warning.code.startsWith("a11y")) return; + handler(warning); + }, + }), + ], + build: { + lib: { + entry: "src/main.ts", + formats: ["cjs"], + fileName: () => "main.js", + }, + rollupOptions: { + plugins: [], + output: { + entryFileNames: "main.js", + assetFileNames: "styles.css", + sourcemapBaseUrl: new URL(setOutDir(mode), import.meta.url).toString(), + manualChunks: undefined, + inlineDynamicImports: true, + }, + external: [ + "obsidian", + "electron", + "@codemirror/autocomplete", + "@codemirror/collab", + "@codemirror/commands", + "@codemirror/language", + "@codemirror/lint", + "@codemirror/search", + "@codemirror/state", + "@codemirror/view", + "@lezer/common", + "@lezer/highlight", + "@lezer/lr", + ...builtinModules, + ], + }, + outDir: setOutDir(mode), + emptyOutDir: mode === "production", + sourcemap: isDevelopment, + }, + css: { + devSourcemap: isDevelopment, + }, + }; });