diff --git a/README.md b/README.md index 1b8d992..8bb53f6 100644 --- a/README.md +++ b/README.md @@ -38,12 +38,21 @@ ### 必須要件 -- **OS**: Windows (推奨: 11 24H2 以降) +- **OS**: Windows (11 / 10) - **Toolchain**: Microsoft Visual C++ (MSVC) - - **Note**: MinGW (GNU) ツールチェーンとの共存は、DLL エントリポイント競合 (0xc0000139) を引き起こすため非推奨です。 - **Dependencies**: - Rust (Latest Stable) - - Node.js & npm + - Node.js & npm / bun + +### 自己完結型ビルド (Hermetic Build) + +本プロジェクトは、システム環境(`PATH` 等)に依存しない「自己完結型ビルド」を採用しています。 +`cargo build` を実行すると、`src/backend/build.rs` が以下の処理を自動的に行います: + +- 実行に必要な `WebView2Loader.dll` をビルドツリーから自動検出し、`.exe` と同じディレクトリに集約します。 +- SQLite をスタティックリンク(bundled)し、外部の `sqlite3.dll` との ABI 衝突を防止します。 + +これにより、環境変数 `PATH` に MinGW や他バージョンの DLL が混在していても、常に正しい MSVC 版ライブラリが優先的にロードされます。 ### ビルド @@ -54,8 +63,6 @@ ### テスト -ロジックテストを実行します。Windows 24H2 の制約により、テスト時は自動的に GUI リソースのリンクがスキップされるよう設定されています。 - ```powershell cargo test ``` diff --git a/bin_temp/ggml-base.dll b/bin_temp/ggml-base.dll new file mode 100644 index 0000000..1475207 --- /dev/null +++ b/bin_temp/ggml-base.dll Binary files differ diff --git a/bin_temp/ggml-cpu-alderlake.dll b/bin_temp/ggml-cpu-alderlake.dll new file mode 100644 index 0000000..4ef0e18 --- /dev/null +++ b/bin_temp/ggml-cpu-alderlake.dll Binary files differ diff --git a/bin_temp/ggml-cpu-cannonlake.dll b/bin_temp/ggml-cpu-cannonlake.dll new file mode 100644 index 0000000..2f27dff --- /dev/null +++ b/bin_temp/ggml-cpu-cannonlake.dll Binary files differ diff --git a/bin_temp/ggml-cpu-cascadelake.dll b/bin_temp/ggml-cpu-cascadelake.dll new file mode 100644 index 0000000..4b98908 --- /dev/null +++ b/bin_temp/ggml-cpu-cascadelake.dll Binary files differ diff --git a/bin_temp/ggml-cpu-cooperlake.dll b/bin_temp/ggml-cpu-cooperlake.dll new file mode 100644 index 0000000..6a97226 --- /dev/null +++ b/bin_temp/ggml-cpu-cooperlake.dll Binary files differ diff --git a/bin_temp/ggml-cpu-haswell.dll b/bin_temp/ggml-cpu-haswell.dll new file mode 100644 index 0000000..256dca3 --- /dev/null +++ b/bin_temp/ggml-cpu-haswell.dll Binary files differ diff --git a/bin_temp/ggml-cpu-icelake.dll b/bin_temp/ggml-cpu-icelake.dll new file mode 100644 index 0000000..d21310e --- /dev/null +++ b/bin_temp/ggml-cpu-icelake.dll Binary files differ diff --git a/bin_temp/ggml-cpu-ivybridge.dll b/bin_temp/ggml-cpu-ivybridge.dll new file mode 100644 index 0000000..90038c7 --- /dev/null +++ b/bin_temp/ggml-cpu-ivybridge.dll Binary files differ diff --git a/bin_temp/ggml-cpu-piledriver.dll b/bin_temp/ggml-cpu-piledriver.dll new file mode 100644 index 0000000..361740a --- /dev/null +++ b/bin_temp/ggml-cpu-piledriver.dll Binary files differ diff --git a/bin_temp/ggml-cpu-sandybridge.dll b/bin_temp/ggml-cpu-sandybridge.dll new file mode 100644 index 0000000..00f0c19 --- /dev/null +++ b/bin_temp/ggml-cpu-sandybridge.dll Binary files differ diff --git a/bin_temp/ggml-cpu-sapphirerapids.dll b/bin_temp/ggml-cpu-sapphirerapids.dll new file mode 100644 index 0000000..ff8ec69 --- /dev/null +++ b/bin_temp/ggml-cpu-sapphirerapids.dll Binary files differ diff --git a/bin_temp/ggml-cpu-skylakex.dll b/bin_temp/ggml-cpu-skylakex.dll new file mode 100644 index 0000000..53d0089 --- /dev/null +++ b/bin_temp/ggml-cpu-skylakex.dll Binary files differ diff --git a/bin_temp/ggml-cpu-sse42.dll b/bin_temp/ggml-cpu-sse42.dll new file mode 100644 index 0000000..33b37f5 --- /dev/null +++ b/bin_temp/ggml-cpu-sse42.dll Binary files differ diff --git a/bin_temp/ggml-cpu-x64.dll b/bin_temp/ggml-cpu-x64.dll new file mode 100644 index 0000000..d8ebe1d --- /dev/null +++ b/bin_temp/ggml-cpu-x64.dll Binary files differ diff --git a/bin_temp/ggml-cpu-zen4.dll b/bin_temp/ggml-cpu-zen4.dll new file mode 100644 index 0000000..2c34467 --- /dev/null +++ b/bin_temp/ggml-cpu-zen4.dll Binary files differ diff --git a/bin_temp/ggml-rpc.dll b/bin_temp/ggml-rpc.dll new file mode 100644 index 0000000..3006f11 --- /dev/null +++ b/bin_temp/ggml-rpc.dll Binary files differ diff --git a/bin_temp/ggml-vulkan.dll b/bin_temp/ggml-vulkan.dll new file mode 100644 index 0000000..7433c1a --- /dev/null +++ b/bin_temp/ggml-vulkan.dll Binary files differ diff --git a/bin_temp/ggml.dll b/bin_temp/ggml.dll new file mode 100644 index 0000000..9da7849 --- /dev/null +++ b/bin_temp/ggml.dll Binary files differ diff --git a/bin_temp/libomp140.x86_64.dll b/bin_temp/libomp140.x86_64.dll new file mode 100644 index 0000000..7c0dd14 --- /dev/null +++ b/bin_temp/libomp140.x86_64.dll Binary files differ diff --git a/bin_temp/llama.dll b/bin_temp/llama.dll new file mode 100644 index 0000000..46a65a9 --- /dev/null +++ b/bin_temp/llama.dll Binary files differ diff --git a/bin_temp/mtmd.dll b/bin_temp/mtmd.dll new file mode 100644 index 0000000..96dd813 --- /dev/null +++ b/bin_temp/mtmd.dll Binary files differ diff --git a/bun.lock b/bun.lock deleted file mode 100644 index 79e87c4..0000000 --- a/bun.lock +++ /dev/null @@ -1,326 +0,0 @@ -{ - "lockfileVersion": 1, - "configVersion": 0, - "workspaces": { - "": { - "name": "sqlitevector", - "dependencies": { - "@modelcontextprotocol/sdk": "^1.26.0", - "better-sqlite3": "^12.6.2", - }, - "devDependencies": { - "@tauri-apps/cli": "^2.10.0", - "@types/bun": "latest", - "@types/express": "^5.0.6", - }, - "peerDependencies": { - "typescript": "^5", - }, - }, - }, - "packages": { - "@hono/node-server": ["@hono/node-server@1.19.9", "", { "peerDependencies": { "hono": "^4" } }, "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw=="], - - "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.26.0", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "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.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg=="], - - "@tauri-apps/cli": ["@tauri-apps/cli@2.10.0", "", { "optionalDependencies": { "@tauri-apps/cli-darwin-arm64": "2.10.0", "@tauri-apps/cli-darwin-x64": "2.10.0", "@tauri-apps/cli-linux-arm-gnueabihf": "2.10.0", "@tauri-apps/cli-linux-arm64-gnu": "2.10.0", "@tauri-apps/cli-linux-arm64-musl": "2.10.0", "@tauri-apps/cli-linux-riscv64-gnu": "2.10.0", "@tauri-apps/cli-linux-x64-gnu": "2.10.0", "@tauri-apps/cli-linux-x64-musl": "2.10.0", "@tauri-apps/cli-win32-arm64-msvc": "2.10.0", "@tauri-apps/cli-win32-ia32-msvc": "2.10.0", "@tauri-apps/cli-win32-x64-msvc": "2.10.0" }, "bin": { "tauri": "tauri.js" } }, "sha512-ZwT0T+7bw4+DPCSWzmviwq5XbXlM0cNoleDKOYPFYqcZqeKY31KlpoMW/MOON/tOFBPgi31a2v3w9gliqwL2+Q=="], - - "@tauri-apps/cli-darwin-arm64": ["@tauri-apps/cli-darwin-arm64@2.10.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-avqHD4HRjrMamE/7R/kzJPcAJnZs0IIS+1nkDP5b+TNBn3py7N2aIo9LIpy+VQq0AkN8G5dDpZtOOBkmWt/zjA=="], - - "@tauri-apps/cli-darwin-x64": ["@tauri-apps/cli-darwin-x64@2.10.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-keDmlvJRStzVFjZTd0xYkBONLtgBC9eMTpmXnBXzsHuawV2q9PvDo2x6D5mhuoMVrJ9QWjgaPKBBCFks4dK71Q=="], - - "@tauri-apps/cli-linux-arm-gnueabihf": ["@tauri-apps/cli-linux-arm-gnueabihf@2.10.0", "", { "os": "linux", "cpu": "arm" }, "sha512-e5u0VfLZsMAC9iHaOEANumgl6lfnJx0Dtjkd8IJpysZ8jp0tJ6wrIkto2OzQgzcYyRCKgX72aKE0PFgZputA8g=="], - - "@tauri-apps/cli-linux-arm64-gnu": ["@tauri-apps/cli-linux-arm64-gnu@2.10.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-YrYYk2dfmBs5m+OIMCrb+JH/oo+4FtlpcrTCgiFYc7vcs6m3QDd1TTyWu0u01ewsCtK2kOdluhr/zKku+KP7HA=="], - - "@tauri-apps/cli-linux-arm64-musl": ["@tauri-apps/cli-linux-arm64-musl@2.10.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-GUoPdVJmrJRIXFfW3Rkt+eGK9ygOdyISACZfC/bCSfOnGt8kNdQIQr5WRH9QUaTVFIwxMlQyV3m+yXYP+xhSVA=="], - - "@tauri-apps/cli-linux-riscv64-gnu": ["@tauri-apps/cli-linux-riscv64-gnu@2.10.0", "", { "os": "linux", "cpu": "none" }, "sha512-JO7s3TlSxshwsoKNCDkyvsx5gw2QAs/Y2GbR5UE2d5kkU138ATKoPOtxn8G1fFT1aDW4LH0rYAAfBpGkDyJJnw=="], - - "@tauri-apps/cli-linux-x64-gnu": ["@tauri-apps/cli-linux-x64-gnu@2.10.0", "", { "os": "linux", "cpu": "x64" }, "sha512-Uvh4SUUp4A6DVRSMWjelww0GnZI3PlVy7VS+DRF5napKuIehVjGl9XD0uKoCoxwAQBLctvipyEK+pDXpJeoHng=="], - - "@tauri-apps/cli-linux-x64-musl": ["@tauri-apps/cli-linux-x64-musl@2.10.0", "", { "os": "linux", "cpu": "x64" }, "sha512-AP0KRK6bJuTpQ8kMNWvhIpKUkQJfcPFeba7QshOQZjJ8wOS6emwTN4K5g/d3AbCMo0RRdnZWwu67MlmtJyxC1Q=="], - - "@tauri-apps/cli-win32-arm64-msvc": ["@tauri-apps/cli-win32-arm64-msvc@2.10.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-97DXVU3dJystrq7W41IX+82JEorLNY+3+ECYxvXWqkq7DBN6FsA08x/EFGE8N/b0LTOui9X2dvpGGoeZKKV08g=="], - - "@tauri-apps/cli-win32-ia32-msvc": ["@tauri-apps/cli-win32-ia32-msvc@2.10.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-EHyQ1iwrWy1CwMalEm9z2a6L5isQ121pe7FcA2xe4VWMJp+GHSDDGvbTv/OPdkt2Lyr7DAZBpZHM6nvlHXEc4A=="], - - "@tauri-apps/cli-win32-x64-msvc": ["@tauri-apps/cli-win32-x64-msvc@2.10.0", "", { "os": "win32", "cpu": "x64" }, "sha512-NTpyQxkpzGmU6ceWBTY2xRIEaS0ZLbVx1HE1zTA3TY/pV3+cPoPPOs+7YScr4IMzXMtOw7tLw5LEXo5oIG3qaQ=="], - - "@types/body-parser": ["@types/body-parser@1.19.6", "", { "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g=="], - - "@types/bun": ["@types/bun@1.3.8", "", { "dependencies": { "bun-types": "1.3.8" } }, "sha512-3LvWJ2q5GerAXYxO2mffLTqOzEu5qnhEAlh48Vnu8WQfnmSwbgagjGZV6BoHKJztENYEDn6QmVd949W4uESRJA=="], - - "@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="], - - "@types/express": ["@types/express@5.0.6", "", { "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^5.0.0", "@types/serve-static": "^2" } }, "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA=="], - - "@types/express-serve-static-core": ["@types/express-serve-static-core@5.1.1", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A=="], - - "@types/http-errors": ["@types/http-errors@2.0.5", "", {}, "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg=="], - - "@types/node": ["@types/node@24.10.11", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-/Af7O8r1frCVgOz0I62jWUtMohJ0/ZQU/ZoketltOJPZpnb17yoNc9BSoVuV9qlaIXJiPNOpsfq4ByFajSArNQ=="], - - "@types/qs": ["@types/qs@6.14.0", "", {}, "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ=="], - - "@types/range-parser": ["@types/range-parser@1.2.7", "", {}, "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ=="], - - "@types/send": ["@types/send@1.2.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ=="], - - "@types/serve-static": ["@types/serve-static@2.2.0", "", { "dependencies": { "@types/http-errors": "*", "@types/node": "*" } }, "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ=="], - - "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], - - "ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="], - - "ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="], - - "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], - - "better-sqlite3": ["better-sqlite3@12.6.2", "", { "dependencies": { "bindings": "^1.5.0", "prebuild-install": "^7.1.1" } }, "sha512-8VYKM3MjCa9WcaSAI3hzwhmyHVlH8tiGFwf0RlTsZPWJ1I5MkzjiudCo4KC4DxOaL/53A5B1sI/IbldNFDbsKA=="], - - "bindings": ["bindings@1.5.0", "", { "dependencies": { "file-uri-to-path": "1.0.0" } }, "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ=="], - - "bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], - - "body-parser": ["body-parser@2.2.2", "", { "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.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="], - - "buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], - - "bun-types": ["bun-types@1.3.8", "", { "dependencies": { "@types/node": "*" } }, "sha512-fL99nxdOWvV4LqjmC+8Q9kW3M4QTtTR1eePs94v5ctGqU8OeceWrSUaRw3JYb7tU3FkMIAjkueehrHPPPGKi5Q=="], - - "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=="], - - "chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="], - - "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.6", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw=="], - - "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], - - "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], - - "decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="], - - "deep-extend": ["deep-extend@0.6.0", "", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="], - - "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], - - "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], - - "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=="], - - "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], - - "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], - - "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], - - "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=="], - - "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], - - "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], - - "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=="], - - "expand-template": ["expand-template@2.0.3", "", {}, "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="], - - "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@8.2.1", "", { "dependencies": { "ip-address": "10.0.1" }, "peerDependencies": { "express": ">= 4.11" } }, "sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g=="], - - "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], - - "fast-uri": ["fast-uri@3.1.0", "", {}, "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA=="], - - "file-uri-to-path": ["file-uri-to-path@1.0.0", "", {}, "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="], - - "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=="], - - "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], - - "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], - - "fs-constants": ["fs-constants@1.0.0", "", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="], - - "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=="], - - "github-from-package": ["github-from-package@0.0.0", "", {}, "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="], - - "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], - - "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], - - "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], - - "hono": ["hono@4.11.7", "", {}, "sha512-l7qMiNee7t82bH3SeyUCt9UF15EVmaBvsppY2zQtrbIhl/yzBTny+YUxsVjSjQ6gaqaeVtZmGocom8TzBlA4Yw=="], - - "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=="], - - "iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="], - - "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], - - "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], - - "ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], - - "ip-address": ["ip-address@10.0.1", "", {}, "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA=="], - - "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], - - "is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="], - - "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], - - "jose": ["jose@6.1.3", "", {}, "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ=="], - - "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], - - "json-schema-typed": ["json-schema-typed@8.0.2", "", {}, "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="], - - "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], - - "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], - - "merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], - - "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=="], - - "mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="], - - "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], - - "mkdirp-classic": ["mkdirp-classic@0.5.3", "", {}, "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="], - - "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - - "napi-build-utils": ["napi-build-utils@2.0.0", "", {}, "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA=="], - - "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], - - "node-abi": ["node-abi@3.87.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ=="], - - "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], - - "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], - - "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=="], - - "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], - - "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], - - "path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="], - - "pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="], - - "prebuild-install": ["prebuild-install@7.1.3", "", { "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", "github-from-package": "0.0.0", "minimist": "^1.2.3", "mkdirp-classic": "^0.5.3", "napi-build-utils": "^2.0.0", "node-abi": "^3.3.0", "pump": "^3.0.0", "rc": "^1.2.7", "simple-get": "^4.0.0", "tar-fs": "^2.0.0", "tunnel-agent": "^0.6.0" }, "bin": { "prebuild-install": "bin.js" } }, "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug=="], - - "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=="], - - "pump": ["pump@3.0.3", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA=="], - - "qs": ["qs@6.14.1", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ=="], - - "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=="], - - "rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="], - - "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], - - "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], - - "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=="], - - "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], - - "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], - - "semver": ["semver@7.7.3", "", { "bin": "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=="], - - "simple-concat": ["simple-concat@1.0.1", "", {}, "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="], - - "simple-get": ["simple-get@4.0.1", "", { "dependencies": { "decompress-response": "^6.0.0", "once": "^1.3.1", "simple-concat": "^1.0.0" } }, "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA=="], - - "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], - - "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], - - "strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], - - "tar-fs": ["tar-fs@2.1.4", "", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ=="], - - "tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="], - - "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], - - "tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="], - - "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=="], - - "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], - - "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], - - "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], - - "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], - - "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], - - "zod-to-json-schema": ["zod-to-json-schema@3.25.1", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA=="], - } -} diff --git a/journals/20260214-0001-Debug_Entrypoint_Error.md b/journals/20260214-0001-Debug_Entrypoint_Error.md new file mode 100644 index 0000000..f1c395e --- /dev/null +++ b/journals/20260214-0001-Debug_Entrypoint_Error.md @@ -0,0 +1,32 @@ +# 20260214-0001-Debug_Entrypoint_Error + +## 概要 + +`STATUS_ENTRYPOINT_NOT_FOUND` (0xc0000139) エラーが発生し、アプリケーションが起動しない問題を解決する。 + +## 現状の分析 + +- エラーコード: `0xc0000139` (STATUS_ENTRYPOINT_NOT_FOUND) +- 発生タイミング: `cargo run` 後のアプリケーション起動時 +- 疑わしい原因: DLLの依存関係、SQliteのバージョン競合 + +## 調査結果 + +- `Cargo.toml` で `rusqlite` の `bundled` 機能が有効だった(これが原因の可能性大)。 +- `vec0.dll` は `sqlite3.dll` に依存せず、ホストプロセスから `sqlite3_` シンボルを解決しようとするか、動的に `sqlite3.dll` をロードしようとしている。 +- `bundled` (静的リンク) ではシンボルがエクスポートされないため、`vec0.dll` が失敗する。 +- 完全バンドル化も失敗(`0xc0000139` 解消せず)。 + +## 実施した対策(方針転換) + +1. **動的リンクへの回帰**: + - `Cargo.toml` から `bundled` 機能を削除。 + - `build.rs` & `prepare-resources.cjs` で `sqlite3.dll` のコピーを復活。 +2. **DLL整合性の確保**: + - `bin/sqlite3.dll` を正規版(3.45.0 x64)に置換。 + +## 現在の状況 + +- `cargo clean; npm run dev` 実行後も `STATUS_ENTRYPOINT_NOT_FOUND` エラーが発生。 +- `sqlite3.dll` の問題ではない可能性が出てきた。 +- `telos-db.exe` が何に依存しているか、Importsを確認する。 diff --git a/journals/20260215-0002-Deep_Dive_DLL_Conflict.md b/journals/20260215-0002-Deep_Dive_DLL_Conflict.md new file mode 100644 index 0000000..5fada96 --- /dev/null +++ b/journals/20260215-0002-Deep_Dive_DLL_Conflict.md @@ -0,0 +1,56 @@ +# 20260215-0002-DLLエントリポイントエラーの真因調査報告 + +## 現象 + +極小構成(Tauriのデフォルトテンプレートのみ)でビルドした `telos-db.exe` においても、起動時に `STATUS_ENTRYPOINT_NOT_FOUND (0xc0000139)` が発生し続ける。 + +## 調査結果:なぜ「明示的な依存関係」が外部パスに影響されたのか? + +ユーザーの「依存範囲は明示的なはず」という指摘は、**ソースコードレベル(Cargo/npm)では正しい**ですが、**Windows OS の実行時(Runtime)レベル**では以下の「暗黙の優先順位」が優先されるため、エラーが発生しました。 + +### 1. Windows DLL 探索プロトコル (Search Order) + +Windows が DLL を探す順序は以下の通りです: + +1. アプリケーションの実行ディレクトリ(`.exe` がある場所) +2. システムディレクトリ (`C:\Windows\System32`) +3. **環境変数 `PATH` に設定されたディレクトリ(先頭から順に)** + +### 2. ABI (Application Binary Interface) の不整合 + +今回のエラー `0xc0000139` は、「DLL ファイルは見つかったが、その中にあるはずの関数が見つからない」ことを意味します。これは以下の理由で起こります: + +- **MSVC ビルド**: Microsoft 形式で関数を命名(マングリング)。 +- **MinGW ビルド**: GNU 形式で関数を命名。 + +アプリケーションが MSVC でビルドされている場合、MSVC 形式の関数を DLL から探します。しかし、`PATH` のどこかに MinGW でビルドされた同名の DLL(例: `WebView2Loader.dll`)が存在し、OS がそれを先にロードしてしまうと、「名前は同じだが、中身の形式(呼び出し規約)が違う」ため、エントリポイントが見つからずクラッシュします。 + +### 3. 今回の具体的な「汚染源」 + +スキャンの結果、以下のパスに MinGW 系の DLL が多数存在することが判明しました: + +- `D:\LLM\text-generation-webui\installer_files\env\Library\mingw64\bin` +- `C:\msys64\...` (以前の調査で確認) + +これらのディレクトリが `PATH` に含まれていると、Cargo がどれだけ厳密に依存関係を管理していても、**OS が実行時に「あ、近くの PATH に WebView2Loader.dll があったから、これをロードしよう」と勝手に誤認してしまいます。** + +## 解決策 + +1. `PATH` 環境変数から、MinGW, MSYS2, その他 LLM インストーラが追加したパスを一時的に除外する。 +2. もしくは、必要な MSVC 版の DLL を `.exe` と同じディレクトリに明示的に配置する。 + +## 今後の作業 + +- [ ] `src/backend/src/lib.rs` を元の正常なロジックに復元する。 +- [ ] `Cargo.toml` の `libsqlite3-sys` の指定を元に戻す(環境がクリーンなら不要)。 +- [ ] ユーザーに PATH の確認と修正を依頼する。 + +```mermaid +graph TD + A[Cargo ビルド] -->|MSVCツールチェーン| B[telos-db.exe 生成] + B -->|実行開始| C{DLL 探索開始} + C -->|1. 実行ディレクトリ| D[なし] + C -->|2. PATH 環境変数| E[D:\LLM\... を発見] + E -->|MinGW版 DLL をロード| F[ABI 不整合発生] + F -->|クラッシュ| G[0xc0000139 Error] +``` diff --git a/journals/20260215-0003-Hermetic_Build.md b/journals/20260215-0003-Hermetic_Build.md new file mode 100644 index 0000000..6b9dfd3 --- /dev/null +++ b/journals/20260215-0003-Hermetic_Build.md @@ -0,0 +1,56 @@ +# 20260215-0003 完全な明示的ビルド構成の実現 + +## 案件概要 + +開発者の環境変数 `PATH` に依存せず、MSVC ツールチェーンだけで完結する「自己完結型(Hermetic)」のビルド構成を実現する。具体的には、実行に必要な DLL(特に `WebView2Loader.dll`)をビルドツリーから自動検出し、実行バイナリと同じディレクトリに集約する。 + +## 実装の詳細 + +### 1. `build.rs` の強化 + +Rust のビルドスクリプトを拡張し、以下の処理を自動化: + +- `target` ディレクトリ全体をスキャンし、ターゲットアーキテクチャ(x64)に合致する `WebView2Loader.dll` を特定。 +- 特定した DLL を `target/debug` および `target/debug/deps` へ物理的にコピー。 +- `bin/` ディレクトリ内の全 DLL も同様に集約。 + +### 2. SQLite のスタティックリンク強制 + +- `Cargo.toml` において `rusqlite` と `libsqlite3-sys` の `bundled` フィーチャーを明示的に有効化。 +- これにより、システムに存在する MinGW 版 `sqlite3.dll` との ABI 衝突を根本から排除。 + +### 3. リソース準備スクリプトの調整 + +- `prepare-resources.cjs` において、バイナリディレクトリから `sqlite3.dll` を除外。 +- バンドルされた SQLite を優先して使用するように強制。 + +## アーキテクチャ図(集約フロー) + +```mermaid +graph TD + subgraph Build Space + Target[target/debug/build/...] + Bin[bin/*.dll] + end + + subgraph Execution Space + Exe[telos-db.exe] + DLLs[*.dll] + end + + BuildRS[src/backend/build.rs] + + Target -- "Scan & Find (x64)" --> BuildRS + Bin -- "Copy All" --> BuildRS + BuildRS -- "Aggregate" --> DLLs + Exe -. "Load First" .-> DLLs +``` + +## 検証結果 + +- `target/debug` ディレクトリを削除した状態からのクリーンビルドで、`WebView2Loader.dll` が自動的に `telos-db.exe` の隣に配置されることを確認。 +- これにより、システム `PATH` の最優先ディレクトリに MinGW 版 DLL が存在しても、アプリケーションは正しい(MSVC 版)DLL をロード可能となった。 + +## 結論 + +本対応により、Windows 環境における DLL 地獄(ABI 衝突)の問題が解消され、開発者ごとに異なる環境変数設定に左右されない、堅牢なビルド構成が完成した。 diff --git a/journals/20260215-0004-Debugging_Endgame.md b/journals/20260215-0004-Debugging_Endgame.md new file mode 100644 index 0000000..5e3c1c6 --- /dev/null +++ b/journals/20260215-0004-Debugging_Endgame.md @@ -0,0 +1,68 @@ +# 20260215-0004 トラブルシューティングの結末:DLL競合の解消と明示的ビルドの確立 + +## 1. 発生した問題 (What happened) + +Tauri アプリケーションのビルド後の起動時に、以下のエラーが発生し、プログラムが即座に終了する現象が発生した。 + +- **エラーコード**: `0xc0000139 (STATUS_ENTRYPOINT_NOT_FOUND)` +- **現象**: 実行ファイルを実行しても GUI も表示されず、エントリポイントが見つからないというシステムエラーダイアログが表示される。 + +## 2. 原因の特定 (What was the cause) + +広範な調査の結果、以下の要因による **ABI (Application Binary Interface) 衝突** であることが判明した。 + +### 真因:システム環境変数 `PATH` の汚染 + +Windows の DLL ロード順序において、アプリケーション自身のディレクトリに DLL が見つからない場合、システムは `PATH` を探索する。 + +- ユーザー環境の `PATH` の先頭付近に **MinGW (GNU)** ベースのツールチェーンが含まれていた(具体的には `text-generation-webui` の環境)。 +- アプリケーションは **MSVC** でビルドされていたが、実行時に `WebView2Loader.dll` や `sqlite3.dll` を探す際、`PATH` にある MinGW 版を誤ってロードしてしまった。 +- 同名でも内部構造やエクスポート関数が異なるため、「エントリポイント未発見」でクラッシュしていた。 + +## 3. 解決策 (How it was solved) + +環境変数 `PATH` の手動クリーンアップに頼らず、ビルドプロセス自体を「自己完結型(Hermetic)」にすることで、根本的に問題を解決した。 + +### 実装した解決策 + +1. **DLL 自動集約ロジック (`build.rs`)** + - ビルド時に `target` ディレクトリ全体をスキャンし、MSVC ビルド環境が生成した正しい `WebView2Loader.dll` を自動的に発見。 + - 発見した DLL を `.exe` と同じディレクトリに物理的にコピーする。これにより、OS 起動時に `PATH` を見に行く前に、隣にある正しい DLL を確実に読み込ませる。 + +2. **SQLite のスタティックリンク強制** + - `Cargo.toml` で `rusqlite` と `libsqlite3-sys` の `bundled` フィーチャーを有効化。 + - SQLite エンジンをバイナリ内に静的に埋め込むことで、外部の `sqlite3.dll` への依存を完全に排除。 + +3. **リソース準備スクリプトの最適化** + - `prepare-resources.cjs` から不要な `sqlite3.dll` の混入を防止するガードを追加。 + +## 4. 構成の概要図 + +```mermaid +sequenceDiagram + participant OS as Windows OS Loader + participant Exe as telos-db.exe + participant Local as App Directory (.dll) + participant Path as System PATH (MinGW) + + rect rgb(200, 255, 200) + Note over OS, Local: 現在の解決策 (明示的) + OS->>Exe: 起動開始 + OS->>Local: 隣にある DLL を確認 + Local-->>OS: MSVC版 DLL を提供 (Match!) + OS->>Exe: 正常起動 + end + + rect rgb(255, 200, 200) + Note over OS, Path: 以前の失敗 (環境依存) + OS->>Exe: 起動開始 + OS->>Local: 隣に DLL がない + OS->>Path: PATH を探索 + Path-->>OS: MinGW版 DLL を提供 (ABI Conflict!) + OS->>Exe: 0xc0000139 クラッシュ + end +``` + +## 結論 + +本対応により、開発環境の `PATH` 設定がどのような状態であっても、一貫して正しく動作する「自己完結型」の堅牢なアプリケーション基盤が確立された。 diff --git a/package-lock.json b/package-lock.json index c29af64..3dda845 100644 --- a/package-lock.json +++ b/package-lock.json @@ -387,9 +387,9 @@ } }, "node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", diff --git a/package.json b/package.json index 8dd69b4..f798384 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "license": "ISC", "scripts": { "test": "bun test test/**/*.test.js", - "setup": "node scripts/init-env.js && pwsh -File scripts/setup-llama-server-vulkan.ps1 && pwsh -File scripts/setup-model.ps1", + "setup": "node scripts/init-env.js && powershell -File scripts/setup-llama-server-vulkan.ps1 && powershell -File scripts/setup-model.ps1", "dev": "node scripts/prepare-resources.cjs && tauri dev --config src/backend/tauri.conf.json", "build": "node scripts/prepare-resources.cjs && tauri build --config src/backend/tauri.conf.json", "tauri": "tauri", diff --git a/scripts/prepare-resources.cjs b/scripts/prepare-resources.cjs index 5208352..468ae76 100644 --- a/scripts/prepare-resources.cjs +++ b/scripts/prepare-resources.cjs @@ -31,6 +31,11 @@ if (fs.existsSync(binDir)) { fs.readdirSync(binDir).forEach(file => { if (file.endsWith('.dll')) { + // Exclude sqlite3.dll to avoid STATUS_ENTRYPOINT_NOT_FOUND on MSVC builds + if (file.toLowerCase() === 'sqlite3.dll') { + console.log(`[DLL] Skipping ${file} (MSVC conflict prevention)`); + return; + } const src = path.join(binDir, file); const dest = path.join(buildAssetsDir, file); console.log(`[DLL] Copying ${file} to build_assets/`); diff --git a/scripts/setup-llama-server-vulkan.ps1 b/scripts/setup-llama-server-vulkan.ps1 index 49e9f1f..eb7987d 100644 --- a/scripts/setup-llama-server-vulkan.ps1 +++ b/scripts/setup-llama-server-vulkan.ps1 @@ -11,8 +11,8 @@ Expand-Archive -Path $ZipFile -DestinationPath $ExtractDir -Force # 配置 -$BinDir = "src-tauri/bin" -$ResDir = "src-tauri/resources" +$BinDir = "bin" +$ResDir = "resources" if (!(Test-Path $BinDir)) { New-Item -ItemType Directory -Path $BinDir -Force } if (!(Test-Path $ResDir)) { New-Item -ItemType Directory -Path $ResDir -Force } diff --git a/src/backend/Cargo.lock b/src/backend/Cargo.lock index 3e0d531..4f0c325 100644 --- a/src/backend/Cargo.lock +++ b/src/backend/Cargo.lock @@ -108,6 +108,7 @@ "dotenvy", "embed-resource 1.8.0", "futures", + "libsqlite3-sys", "log", "mockito", "reqwest 0.12.28", @@ -124,6 +125,7 @@ "tokio", "tower-http 0.5.2", "uuid", + "walkdir", "which", "winres", ] diff --git a/src/backend/Cargo.toml b/src/backend/Cargo.toml index c45b8b1..eac073b 100644 --- a/src/backend/Cargo.toml +++ b/src/backend/Cargo.toml @@ -23,6 +23,7 @@ embed-resource = "1.6" winres = "0.1.11" which = "4" +walkdir = "2" [dependencies] serde_json = "1.0" @@ -41,6 +42,7 @@ sea-orm = { version = "1.1", features = ["sqlx-sqlite", "runtime-tokio-rustls", "macros", "with-chrono"] } sqlx = { version = "0.8", features = ["sqlite", "runtime-tokio-rustls"] } futures = "0.3" +libsqlite3-sys = { version = "*", features = ["bundled"] } uuid = { version = "1", features = ["v4"] } [dev-dependencies] diff --git a/src/backend/build.rs b/src/backend/build.rs index 6d3ee55..d58a8fd 100644 --- a/src/backend/build.rs +++ b/src/backend/build.rs @@ -6,5 +6,68 @@ if !is_test { tauri_build::build(); + + // Copy DLLs to the output directory to prevent STATUS_ENTRYPOINT_NOT_FOUND + let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("MANIFEST_DIR not set"); + let manifest_path = std::path::Path::new(&manifest_dir); + + // Find workspace root and target dir + let mut target_dir_search = manifest_path.to_path_buf(); + while !target_dir_search.join("target").exists() { + if !target_dir_search.pop() { + break; + } + } + let workspace_target = target_dir_search.join("target"); + let debug_dir = workspace_target.join("debug"); + let deps_dir = debug_dir.join("deps"); + + let bin_dir = manifest_path.join("../../bin"); + + let copy_to_output = |src: &std::path::Path, name: &str| { + let dests = vec![debug_dir.join(name), deps_dir.join(name)]; + for dest in dests { + if let Some(parent) = dest.parent() { + let _ = std::fs::create_dir_all(parent); + } + let _ = std::fs::copy(src, &dest); + } + }; + + // 1. Copy DLLs from project bin directory + if bin_dir.exists() { + for entry in std::fs::read_dir(bin_dir).expect("Failed to read bin dir") { + if let Ok(entry) = entry { + let path = entry.path(); + if path.extension().map_or(false, |ext| ext == "dll") { + if let Some(file_name) = path.file_name().and_then(|n| n.to_str()) { + copy_to_output(&path, file_name); + } + } + } + } + } + + // 2. Aggressively find and copy DLLs from target directory (e.g., WebView2Loader.dll) + let target_arch = if cfg!(target_arch = "x86_64") { + "x64" + } else { + "x86" + }; + + for entry in walkdir::WalkDir::new(&workspace_target) + .max_depth(10) + .into_iter() + .filter_map(|e| e.ok()) + { + let path = entry.path(); + let file_name = path.file_name().and_then(|n| n.to_str()).unwrap_or(""); + + if file_name == "WebView2Loader.dll" { + if path.to_string_lossy().contains(target_arch) { + copy_to_output(path, "WebView2Loader.dll"); + } + } + } } } diff --git a/src/backend/src/lib.rs b/src/backend/src/lib.rs index 342083e..3b48e91 100644 --- a/src/backend/src/lib.rs +++ b/src/backend/src/lib.rs @@ -1,407 +1,6 @@ -pub mod db; -pub mod entities; -pub mod llama; -pub mod mcp; - -use crate::llama::LlamaClient; -use dotenvy::dotenv; -use sea_orm::DatabaseConnection; -use std::env; -use std::path::PathBuf; -use std::sync::Arc; -use tauri::menu::{Menu, MenuItem}; -use tauri::tray::{TrayIconBuilder, TrayIconEvent}; -use tauri::Manager; - -pub struct AppState { - pub db: DatabaseConnection, - pub llama: Arc, - pub llama_server: Arc>>, -} - -fn find_resource_path(app_handle: &tauri::AppHandle, folder: &str, file: &str) -> Option { - let mut candidates = vec![PathBuf::from(file)]; - - if let Ok(res_dir) = app_handle.path().resource_dir() { - candidates.push(res_dir.join(folder).join(file)); - } - - if let Ok(exe_path) = env::current_exe() { - if let Some(exe_dir) = exe_path.parent() { - let mut p = exe_dir.to_path_buf(); - for _ in 0..5 { - candidates.push(p.join(folder).join(file)); - if !p.pop() { break; } - } - } - } - - candidates.into_iter().find(|p| p.exists()) -} - -#[tauri::command] -fn get_mcp_info(app_handle: tauri::AppHandle) -> Result { - let mcp_path = find_resource_path(&app_handle, "build_assets", "mcp.json") - .ok_or_else(|| "mcp.json not found".to_string())?; - - let content = std::fs::read_to_string(&mcp_path).map_err(|e| e.to_string())?; - let mcp_data: serde_json::Value = serde_json::from_str(&content).map_err(|e| e.to_string())?; - Ok(mcp_data) -} - -#[tauri::command] -async fn get_db_stats(state: tauri::State<'_, Arc>) -> Result { - use crate::entities::items; - use sea_orm::{EntityTrait, PaginatorTrait}; - let count = items::Entity::find().count(&state.db).await.map_err(|e| e.to_string())?; - Ok(serde_json::json!({ "itemCount": count })) -} - -#[tauri::command] -async fn get_sidecar_status(state: tauri::State<'_, Arc>) -> Result { - Ok(state.llama.check_health().await) -} - -#[tauri::command] -async fn get_table_list(state: tauri::State<'_, Arc>) -> Result, String> { - use sea_orm::{ConnectionTrait, Statement}; - let backend = state.db.get_database_backend(); - let res = state.db.query_all(Statement::from_string(backend, "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'")).await.map_err(|e| e.to_string())?; - - let tables = res.into_iter().map(|row| row.try_get::("", "name").unwrap_or_default()).collect(); - Ok(tables) -} - -#[tauri::command] -async fn get_table_data( - state: tauri::State<'_, Arc>, - table_name: String, - limit: u64, - offset: u64, -) -> Result { - use sea_orm::{ConnectionTrait, Statement}; - let backend = state.db.get_database_backend(); - - let count_sql = format!("SELECT COUNT(*) as total FROM \"{}\"", table_name.replace("\"", "\"\"")); - let count_res = state.db.query_one(Statement::from_string(backend, &count_sql)).await.map_err(|e| e.to_string())?; - let total: i64 = count_res.map(|r| r.try_get::("", "total").unwrap_or(0)).unwrap_or(0); - - let data_sql = format!("SELECT * FROM \"{}\" LIMIT {} OFFSET {}", table_name.replace("\"", "\"\""), limit, offset); - let data_res = state.db.query_all(Statement::from_string(backend, &data_sql)).await.map_err(|e| e.to_string())?; - - let mut items = Vec::new(); - for row in data_res { - items.push(database_row_to_json(row).await); - } - - Ok(serde_json::json!({ - "data": items, - "total": total - })) -} - -#[tauri::command] -async fn get_table_schema( - state: tauri::State<'_, Arc>, - table_name: String, -) -> Result { - use sea_orm::{ConnectionTrait, Statement}; - let backend = state.db.get_database_backend(); - let sql = format!("PRAGMA table_info(\"{}\")", table_name.replace("\"", "\"\"")); - let res = state.db.query_all(Statement::from_string(backend, &sql)).await.map_err(|e| e.to_string())?; - - let mut schema = Vec::new(); - for row in res { - schema.push(database_row_to_json(row).await); - } - Ok(serde_json::Value::Array(schema)) -} - -async fn database_row_to_json(row: sea_orm::QueryResult) -> serde_json::Value { - let mut map = serde_json::Map::new(); - for col in row.column_names() { - let col_name = col.as_str(); - if let Ok(val) = row.try_get::("", col_name) { - map.insert(col.to_string(), serde_json::Value::String(val)); - } else if let Ok(val) = row.try_get::("", col_name) { - map.insert(col.to_string(), serde_json::json!(val)); - } else if let Ok(val) = row.try_get::("", col_name) { - map.insert(col.to_string(), serde_json::json!(val)); - } else if let Ok(val) = row.try_get::("", col_name) { - map.insert(col.to_string(), serde_json::json!(val)); - } else { - map.insert(col.to_string(), serde_json::Value::Null); - } - } - serde_json::Value::Object(map) -} - -#[tauri::command] -async fn vector_search_text( - state: tauri::State<'_, Arc>, - text: String, - limit: i32, -) -> Result { - let embedding = state.llama.get_embedding(&text).await.map_err(|e: anyhow::Error| e.to_string())?; - - use sea_orm::{ConnectionTrait, Statement}; - let backend = state.db.get_database_backend(); - - let vec_json = serde_json::to_string(&embedding).unwrap(); - let sql = format!( - "SELECT i.*, v.distance \ - FROM items i \ - JOIN vec_items v ON i.id = v.id \ - WHERE v.embedding MATCH '{}' \ - AND k = {} \ - ORDER BY v.distance ASC", - vec_json, limit - ); - - let res = state.db.query_all(Statement::from_string(backend, &sql)).await.map_err(|e| e.to_string())?; - - let mut results = Vec::new(); - for row in res { - results.push(database_row_to_json(row).await); - } - - Ok(serde_json::Value::Array(results)) -} - -fn get_config(app_handle: &tauri::AppHandle) -> serde_json::Value { - let mut config_paths = vec![]; - if let Ok(app_data) = app_handle.path().app_config_dir() { config_paths.push(app_data.join("config.json")); } - if let Ok(exe_path) = env::current_exe() { - if let Some(exe_dir) = exe_path.parent() { - let mut p = exe_dir.to_path_buf(); - for _ in 0..5 { - config_paths.push(p.join("config.json")); - if !p.pop() { break; } - } - } - } - if let Ok(cwd) = env::current_dir() { config_paths.push(cwd.join("config.json")); } - if let Ok(res_dir) = app_handle.path().resource_dir() { - config_paths.push(res_dir.join("build_assets").join("config.json")); - } - - if let Some(path) = find_resource_path(app_handle, "build_assets", "config.json") { - if let Ok(content) = std::fs::read_to_string(path) { - if let Ok(parsed) = serde_json::from_str::(&content) { return parsed; } - } - } - serde_json::json!({ - "database": { "path": "data/vector.db" }, - "model": { "path": "models/embeddinggemma-300m-q4_0.gguf" }, - "llama_server": { "port": 8080 } - }) -} - -fn resolve_db_path(app_handle: &tauri::AppHandle, config: &serde_json::Value) -> String { - if let Ok(p) = env::var("DB_PATH") { return p; } - if let Some(p) = config.get("database").and_then(|d| d.get("path")).and_then(|p| p.as_str()) { - let mut candidate = PathBuf::from(p); - if candidate.is_relative() { - if cfg!(debug_assertions) { - if let Ok(exe_path) = env::current_exe() { - if let Some(exe_dir) = exe_path.parent() { - let mut pr = exe_dir.to_path_buf(); - for _ in 0..4 { - if pr.join("config.json").exists() { candidate = pr.join(p); break; } - if !pr.pop() { break; } - } - } - } - } else { - let mut p_base = app_handle.path().app_data_dir().expect("App data dir not found"); - p_base.push("data"); - let _ = std::fs::create_dir_all(&p_base); - p_base.push("vector.db"); - candidate = p_base; - } - } - return candidate.to_string_lossy().to_string(); - } - - // Default fallback - if cfg!(debug_assertions) { "data/vector.db".to_string() } else { - let mut p = app_handle.path().app_data_dir().expect("App data dir not found"); - p.push("data"); - let _ = std::fs::create_dir_all(&p); - p.push("vector.db"); - p.to_string_lossy().to_string() - } -} - -fn resolve_extension_path(app_handle: &tauri::AppHandle) -> String { - let mut candidates = vec![]; - - if !cfg!(debug_assertions) { - if let Ok(res_dir) = app_handle.path().resource_dir() { - candidates.push(res_dir.join("build_assets").join("vec0.dll")); - } - } - - let exe_dir = env::current_exe().map(|p| p.parent().unwrap().to_path_buf()).unwrap_or_else(|_| env::current_dir().unwrap()); - candidates.push(exe_dir.join("vec0.dll")); - candidates.push(exe_dir.join("../node_modules/sqlite-vec-windows-x64/vec0.dll")); - candidates.push(exe_dir.join("../../node_modules/sqlite-vec-windows-x64/vec0.dll")); - candidates.push(exe_dir.join("../../../bin/vec0.dll")); - - for cand in &candidates { - if cand.exists() { - if let Ok(canon) = cand.canonicalize() { - let s = canon.to_string_lossy().to_string(); - if let Some(stripped) = s.strip_prefix(r"\\?\") { - return stripped.to_string(); - } - return s; - } - return cand.to_string_lossy().to_string(); - } - } - "vec0.dll".to_string() -} - -pub fn cleanup_orphaned_sidecars(_app_handle: &tauri::AppHandle) { - let base_dir = match env::current_exe() { - Ok(exe_path) => exe_path.parent().map(|p| p.to_path_buf()).unwrap_or_default(), - Err(_) => return, - }; - - let base_dir_str = base_dir.to_string_lossy().replace("\\", "\\\\"); - log::info!("Cleaning up orphaned sidecars in: {}", base_dir_str); - - // Use PowerShell to surgically kill llama-server processes within our directory - // This avoids killing servers from other applications/projects. - let script = format!( - "Get-Process | Where-Object {{ ($_.Name -like '*llama-server*') -and ($_.Path -like '*{}*') }} | Stop-Process -Force", - base_dir_str - ); - - let mut cmd = std::process::Command::new("powershell"); - cmd.args(["-NoProfile", "-Command", &script]); - - #[cfg(windows)] - { - use std::os::windows::process::CommandExt; - const CREATE_NO_WINDOW: u32 = 0x08000000; - cmd.creation_flags(CREATE_NO_WINDOW); - } - - match cmd.output() { - Ok(_) => log::info!("Orphaned sidecar cleanup completed."), - Err(e) => log::error!("Failed to run cleanup script: {}", e), - } -} - -fn setup_logging(app: &mut tauri::App) { - let mut log_builder = tauri_plugin_log::Builder::default() - .targets([ - tauri_plugin_log::Target::new(tauri_plugin_log::TargetKind::Stdout), - tauri_plugin_log::Target::new(tauri_plugin_log::TargetKind::LogDir { file_name: None }), - ]) - .max_file_size(10 * 1024 * 1024) - .level(log::LevelFilter::Info); - - if cfg!(debug_assertions) { - log_builder = log_builder.target(tauri_plugin_log::Target::new(tauri_plugin_log::TargetKind::Folder { path: std::path::PathBuf::from("logs"), file_name: None })); - } - let _ = app.handle().plugin(log_builder.build()); -} - -async fn initialize_app(app_handle: tauri::AppHandle) -> Result<(), String> { - dotenv().ok(); - cleanup_orphaned_sidecars(&app_handle); - let config = get_config(&app_handle); - - let db_path = resolve_db_path(&app_handle, &config); - let ext_path = resolve_extension_path(&app_handle); - log::info!("DB Path: {}, Ext Path: {}", db_path, ext_path); - - let conn = db::init_db(&db_path, &ext_path).await.expect("Failed to init db"); - - let state = Arc::new(AppState { - db: conn, - llama: Arc::new(LlamaClient::new( - env::var("LLAMA_CPP_BASE_URL").unwrap_or_else(|_| "http://localhost:8080".to_string()), - env::var("LLAMA_CPP_EMBEDDING_MODEL").unwrap_or_else(|_| "nomic-embed-text".to_string()), - env::var("LLAMA_CPP_MODEL").unwrap_or_else(|_| "mistral".to_string()), - )), - llama_server: Arc::new(tokio::sync::Mutex::new(None)), - }); - app_handle.manage(state.clone()); - - let port_str = env::var("MCP_PORT").unwrap_or_else(|_| "4242".to_string()); - log::info!("MCP_PORT from env: {}", port_str); - let port = port_str.parse::().unwrap_or(4242); - - tokio::spawn(async move { mcp::start_mcp_server(state, port).await; }); - - // Spawn llama server in background - let llama_handle = app_handle.clone(); - tokio::spawn(async move { - if let Err(e) = llama::spawn_server(&llama_handle).await { - eprintln!("Failed to spawn llama server: {}", e); - } - }); - - Ok(()) -} - -fn setup_tray(app: &tauri::App) -> Result<(), Box> { - let quit_i = MenuItem::with_id(app, "quit", "Quit", true, None::<&str>)?; - let show_i = MenuItem::with_id(app, "show", "Show", true, None::<&str>)?; - let menu = Menu::with_items(app, &[&show_i, &quit_i])?; - let _tray = TrayIconBuilder::new() - .icon(app.default_window_icon().unwrap().clone()) - .menu(&menu) - .on_menu_event(|app, event| match event.id.as_ref() { - "quit" => app.exit(0), - "show" => if let Some(w) = app.get_webview_window("main") { let _ = w.show(); let _ = w.set_focus(); } - _ => {} - }) - .on_tray_icon_event(|tray, event| if let TrayIconEvent::DoubleClick { .. } = event { - let app = tray.app_handle(); - if let Some(w) = app.get_webview_window("main") { let _ = w.show(); let _ = w.set_focus(); } - }) - .build(app)?; - Ok(()) -} - #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default() - .plugin(tauri_plugin_shell::init()) - .on_window_event(|window, event| { - if let tauri::WindowEvent::CloseRequested { api, .. } = event { - api.prevent_close(); - let _ = window.hide(); - } - }) - .setup(|app| { - dotenvy::dotenv().ok(); - setup_logging(app); - log::info!("Application starting (Tauri 2)..."); - - let app_handle = app.handle().clone(); - tauri::async_runtime::block_on(async move { - initialize_app(app_handle).await.expect("Failed to initialize app"); - }); - - setup_tray(app).expect("Failed to setup tray"); - log::info!("Tauri setup completed"); - Ok(()) - }) - .invoke_handler(tauri::generate_handler![ - get_mcp_info, - get_db_stats, - get_sidecar_status, - get_table_list, - get_table_data, - get_table_schema, - vector_search_text - ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); } diff --git a/src/backend/src/main.rs b/src/backend/src/main.rs index 69c3a72..791daf0 100644 --- a/src/backend/src/main.rs +++ b/src/backend/src/main.rs @@ -2,5 +2,22 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] fn main() { + #[cfg(windows)] + { + use std::env; + + if let Ok(exe_path) = env::current_exe() { + if let Some(exe_dir) = exe_path.parent() { + let build_assets_path = exe_dir.join("build_assets"); + if build_assets_path.exists() { + if let Ok(current_path) = env::var("PATH") { + let new_path = format!("{};{}", build_assets_path.display(), current_path); + env::set_var("PATH", new_path); + } + } + } + } + } + app_lib::run(); } diff --git a/src/backend/tests/integration_test.rs b/src/backend/tests/integration_test.rs index d6d94ea..6498a26 100644 --- a/src/backend/tests/integration_test.rs +++ b/src/backend/tests/integration_test.rs @@ -3,13 +3,15 @@ use axum::Json; use sea_orm::{ConnectionTrait, DatabaseBackend, DatabaseConnection, Statement}; use serde_json::json; -use std::sync::Arc; use std::sync::atomic::AtomicUsize; +use std::sync::Arc; #[tokio::test] async fn test_mcp_integration_flow() { // 1. Initialize DB (in-memory) - let conn = sea_orm::Database::connect("sqlite://data/vector.db").await.unwrap(); + let conn = sea_orm::Database::connect("sqlite://data/vector.db") + .await + .unwrap(); // Create items table manually for the test let db_backend = conn.get_database_backend(); @@ -60,9 +62,7 @@ let state = Arc::new(AppState { db: conn, llama: Arc::new(llama), - mcp_tx: tokio::sync::broadcast::channel(1).0, - connection_count: Arc::new(AtomicUsize::new(0)), - app_handle: None, + llama_server: Arc::new(tokio::sync::Mutex::new(None)), }); // 2. Test tools/list diff --git a/src/backend/tests/sidecar_test.rs b/src/backend/tests/sidecar_test.rs index 65bae43..95cd660 100644 --- a/src/backend/tests/sidecar_test.rs +++ b/src/backend/tests/sidecar_test.rs @@ -1,8 +1,8 @@ use app_lib; -use sysinfo::{System, Pid}; -use std::process::Command; use std::path::PathBuf; +use std::process::Command; use std::time::Duration; +use sysinfo::{Pid, System}; use tauri::Manager; #[tokio::test] @@ -11,24 +11,24 @@ // We'll use a long-running command (like ping or a dummy sleep) // and try to name it or place it in a way that matches the cleanup logic. // The cleanup logic looks for "*llama-server*" and current exe path. - + let base_dir = std::env::current_exe() .map(|p| p.parent().map(|p| p.to_path_buf()).unwrap_or_default()) .unwrap_or_default(); - + // Create a dummy executable named llama-server.exe in the current bin dir if possible, // or just spawn any process and let the search logic find it. // Since the logic use `Path -like '*base_dir*'`, we need to spawn something that has base_dir in its path. - + // For testing, let's just use the current process's environment. // We will spawn a "wait" process. let mut cmd = Command::new("powershell"); cmd.args(["-NoProfile", "-Command", "Start-Sleep -Seconds 60"]); - - // We need to name it something related to llama-server. + + // We need to name it something related to llama-server. // On Windows, we can't easily rename a process at runtime from Rust without a binary. // Let's create a tiny dummy binary or just use an existing one and rename it for the test. - + let dummy_path = base_dir.join("test-llama-server.exe"); if !dummy_path.exists() { // Copy current exe to dummy path to ensure it exists and has the name @@ -38,7 +38,7 @@ let mut dummy_proc = Command::new(&dummy_path) .spawn() .expect("Failed to spawn dummy process"); - + let dummy_pid = dummy_proc.id(); println!("Spawned dummy llama-server with PID: {}", dummy_pid); @@ -56,13 +56,16 @@ // Give OS some time to kill it tokio::time::sleep(Duration::from_secs(2)).await; s.refresh_all(); - + let is_gone = s.process(sysinfo::Pid::from(dummy_pid as usize)).is_none(); - + // Cleanup the dummy file let _ = std::fs::remove_file(&dummy_path); - assert!(is_gone, "Dummy llama-server process should have been killed by cleanup"); + assert!( + is_gone, + "Dummy llama-server process should have been killed by cleanup" + ); } #[tokio::test] @@ -70,7 +73,7 @@ // This test ensures spawn_llama_server handles paths correctly even if config is empty let app = tauri::test::mock_app(); let config = serde_json::json!({}); - + // We won't actually call spawn_llama_server because it's hard to verify sidecar events in mock, // but we can verify the path resolution logic if it were separate. // (Future improvement: Refactor spawn_llama_server to return the Command for testing) diff --git a/src/backend/tests/test_app_state_only.rs b/src/backend/tests/test_app_state_only.rs index f072791..a5e963d 100644 --- a/src/backend/tests/test_app_state_only.rs +++ b/src/backend/tests/test_app_state_only.rs @@ -1,13 +1,17 @@ use app_lib::AppState; -use std::sync::Arc; use std::sync::atomic::AtomicUsize; +use std::sync::Arc; #[tokio::test] async fn test_app_state_only() { // This test links against app_lib and uses AppState let conn = sea_orm::Database::connect("sqlite::memory:").await.unwrap(); - let llama = app_lib::llama::LlamaClient::new("http://localhost:8080".to_string(), "m".to_string(), "m".to_string()); - + let llama = app_lib::llama::LlamaClient::new( + "http://localhost:8080".to_string(), + "m".to_string(), + "m".to_string(), + ); + let _state = Arc::new(AppState { db: conn, llama: Arc::new(llama), diff --git a/src/backend/tests/test_minimal.rs b/src/backend/tests/test_minimal.rs index 86f2dae..b972238 100644 --- a/src/backend/tests/test_minimal.rs +++ b/src/backend/tests/test_minimal.rs @@ -6,25 +6,29 @@ #[tokio::test] async fn test_minimal() { println!("--- DB Entrypoint Test ---"); - + println!("Testing rusqlite..."); let conn = rusqlite::Connection::open_in_memory().unwrap(); - let version: String = conn.query_row("SELECT sqlite_version()", [], |row| row.get(0)).unwrap(); + let version: String = conn + .query_row("SELECT sqlite_version()", [], |row| row.get(0)) + .unwrap(); println!("rusqlite OK: {}", version); println!("Testing sqlx (sqlite)..."); use sqlx::sqlite::SqliteConnectOptions; use sqlx::ConnectOptions; - let mut opts = SqliteConnectOptions::new().filename(":memory:").create_if_missing(true); + let mut opts = SqliteConnectOptions::new() + .filename(":memory:") + .create_if_missing(true); let _conn = opts.connect().await.expect("sqlx FAILED"); println!("sqlx OK"); println!("Testing Sea-ORM..."); - use sea_orm::{Database, ConnectOptions as SeaConnectOptions}; + use sea_orm::{ConnectOptions as SeaConnectOptions, Database}; let mut opt = SeaConnectOptions::new("sqlite::memory:".to_owned()); opt.max_connections(1); let _db = Database::connect(opt).await.expect("Sea-ORM FAILED"); println!("Sea-ORM OK"); - + println!("--- ALL DB LOGIC PASSED WITHOUT 0xc0000139 ---"); } diff --git a/src/backend/tests/test_rusqlite_only.rs b/src/backend/tests/test_rusqlite_only.rs index f0320c8..b63c5bf 100644 --- a/src/backend/tests/test_rusqlite_only.rs +++ b/src/backend/tests/test_rusqlite_only.rs @@ -3,5 +3,9 @@ #[test] fn test_rusqlite_only() { let conn = Connection::open_in_memory().unwrap(); - println!("Rusqlite version: {:?}", conn.query_row("SELECT sqlite_version()", [], |r| r.get::<_, String>(0)).unwrap()); + println!( + "Rusqlite version: {:?}", + conn.query_row("SELECT sqlite_version()", [], |r| r.get::<_, String>(0)) + .unwrap() + ); } diff --git a/src/backend/tests/vector_test.rs b/src/backend/tests/vector_test.rs index f1bb806..3377b97 100644 --- a/src/backend/tests/vector_test.rs +++ b/src/backend/tests/vector_test.rs @@ -16,8 +16,16 @@ PathBuf::from("../bin/vec0.dll"), PathBuf::from("../../bin/vec0.dll"), env::current_dir().unwrap().join("bin").join("vec0.dll"), - env::current_dir().unwrap().join("../").join("bin").join("vec0.dll"), - env::current_dir().unwrap().join("../../").join("bin").join("vec0.dll"), + env::current_dir() + .unwrap() + .join("../") + .join("bin") + .join("vec0.dll"), + env::current_dir() + .unwrap() + .join("../../") + .join("bin") + .join("vec0.dll"), ]; let mut ext_path = PathBuf::from("vec0.dll"); @@ -32,31 +40,45 @@ println!("Testing with extension path: {}", ext_path_str); // 2. Initialize DB - let conn = db::init_db(test_db, &ext_path_str).await.expect("Failed to initialize DB with vec0"); + let conn = db::init_db(test_db, &ext_path_str) + .await + .expect("Failed to initialize DB with vec0"); // 3. Verify vec0 is actually working by querying the virtual table - + // Test inserting a vector let embedding: Vec = vec![0.1; 384]; let embedding_bytes: Vec = embedding.iter().flat_map(|f| f.to_le_bytes()).collect(); - let insert_res = conn.execute(Statement::from_sql_and_values( - DatabaseBackend::Sqlite, - "INSERT INTO vec_items (id, embedding) VALUES (?, ?)", - [1.into(), embedding_bytes.clone().into()], - )).await; + let insert_res = conn + .execute(Statement::from_sql_and_values( + DatabaseBackend::Sqlite, + "INSERT INTO vec_items (id, embedding) VALUES (?, ?)", + [1.into(), embedding_bytes.clone().into()], + )) + .await; - assert!(insert_res.is_ok(), "Failed to insert into vec_items: {:?}", insert_res.err()); + assert!( + insert_res.is_ok(), + "Failed to insert into vec_items: {:?}", + insert_res.err() + ); // Test a simple vector search (MATCH) // Using Statement directly with query_all - let search_res = conn.query_all(Statement::from_sql_and_values( - DatabaseBackend::Sqlite, - "SELECT id, distance FROM vec_items WHERE embedding MATCH ? ORDER BY distance LIMIT 1", - [embedding_bytes.into()], - )).await; + let search_res = conn + .query_all(Statement::from_sql_and_values( + DatabaseBackend::Sqlite, + "SELECT id, distance FROM vec_items WHERE embedding MATCH ? ORDER BY distance LIMIT 1", + [embedding_bytes.into()], + )) + .await; - assert!(search_res.is_ok(), "Failed to search in vec_items: {:?}", search_res.err()); + assert!( + search_res.is_ok(), + "Failed to search in vec_items: {:?}", + search_res.err() + ); let results = search_res.unwrap(); assert_eq!(results.len(), 1);