diff --git a/.github/workflows/build-and-upload.yml b/.github/workflows/build-and-upload.yml index 9121c5f7..dfad1d06 100644 --- a/.github/workflows/build-and-upload.yml +++ b/.github/workflows/build-and-upload.yml @@ -53,7 +53,7 @@ on: # least-privilege (e.g. dev CI uses read-only; releases grant write). env: - NODE_VERSION: 20 + NODE_VERSION: 22 jobs: build-macos: @@ -372,7 +372,7 @@ jobs: if [ "$attempt" -gt 1 ]; then echo "Retrying Tauri CLI install (attempt $attempt)..." fi - npm install @tauri-apps/cli@2.9.4 @tauri-apps/cli-darwin-x64@2.9.4 --no-save --no-audit --no-fund --workspaces=false + npm install @tauri-apps/cli@2.10.1 @tauri-apps/cli-darwin-x64@2.10.1 --no-save --no-audit --no-fund --workspaces=false node -e "require('@tauri-apps/cli'); console.log('Tauri CLI loaded')" && exit 0 done echo "Tauri CLI failed to load after retries" >&2 @@ -456,7 +456,7 @@ jobs: if [ "$attempt" -gt 1 ]; then echo "Retrying Tauri CLI install (attempt $attempt)..." fi - npm install @tauri-apps/cli@2.9.4 @tauri-apps/cli-darwin-arm64@2.9.4 --no-save --no-audit --no-fund --workspaces=false + npm install @tauri-apps/cli@2.10.1 @tauri-apps/cli-darwin-arm64@2.10.1 --no-save --no-audit --no-fund --workspaces=false node -e "require('@tauri-apps/cli'); console.log('Tauri CLI loaded')" && exit 0 done echo "Tauri CLI failed to load after retries" >&2 @@ -542,7 +542,7 @@ jobs: if [ "$attempt" -gt 1 ]; then echo "Retrying Tauri CLI install (attempt $attempt)..." fi - npm install @tauri-apps/cli@2.9.4 @tauri-apps/cli-win32-x64-msvc@2.9.4 --no-save --no-audit --no-fund --workspaces=false + npm install @tauri-apps/cli@2.10.1 @tauri-apps/cli-win32-x64-msvc@2.10.1 --no-save --no-audit --no-fund --workspaces=false node -e "require('@tauri-apps/cli'); console.log('Tauri CLI loaded')" && exit 0 done echo "Tauri CLI failed to load after retries" >&2 @@ -614,6 +614,7 @@ jobs: sudo apt-get install -y \ build-essential \ pkg-config \ + xdg-utils \ libgtk-3-dev \ libglib2.0-dev \ libwebkit2gtk-4.1-dev \ @@ -642,6 +643,7 @@ jobs: if [ "$attempt" -gt 1 ]; then echo "Retrying Tauri CLI install (attempt $attempt)..." fi + # Tauri CLI 2.10.1 regresses Linux AppImage bundling in CI; keep Linux on the last known-good CLI. npm install @tauri-apps/cli@2.9.4 @tauri-apps/cli-linux-x64-gnu@2.9.4 --no-save --no-audit --no-fund --workspaces=false node -e "require('@tauri-apps/cli'); console.log('Tauri CLI loaded')" && exit 0 done @@ -741,6 +743,7 @@ jobs: sudo apt-get install -y \ build-essential \ pkg-config \ + xdg-utils \ gcc-aarch64-linux-gnu \ g++-aarch64-linux-gnu \ libgtk-3-dev:arm64 \ diff --git a/.github/workflows/manual-npm-publish.yml b/.github/workflows/manual-npm-publish.yml index 51f5a328..34a12246 100644 --- a/.github/workflows/manual-npm-publish.yml +++ b/.github/workflows/manual-npm-publish.yml @@ -46,7 +46,7 @@ jobs: publish: runs-on: ubuntu-latest env: - NODE_VERSION: 20 + NODE_VERSION: 22 steps: - name: Checkout uses: actions/checkout@v4 diff --git a/.github/workflows/release-ui.yml b/.github/workflows/release-ui.yml index 2a021832..abe659c5 100644 --- a/.github/workflows/release-ui.yml +++ b/.github/workflows/release-ui.yml @@ -14,7 +14,7 @@ permissions: contents: read env: - NODE_VERSION: 20 + NODE_VERSION: 22 jobs: release-ui: diff --git a/.github/workflows/reusable-release.yml b/.github/workflows/reusable-release.yml index e839e76b..f6e14cea 100644 --- a/.github/workflows/reusable-release.yml +++ b/.github/workflows/reusable-release.yml @@ -39,7 +39,7 @@ permissions: contents: write env: - NODE_VERSION: 20 + NODE_VERSION: 22 jobs: prepare-release: diff --git a/package-lock.json b/package-lock.json index 6e9afbcf..3e28d769 100644 --- a/package-lock.json +++ b/package-lock.json @@ -72,7 +72,6 @@ "version": "7.28.5", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -1891,23 +1890,46 @@ } }, "node_modules/@fastify/accept-negotiator": { - "version": "1.1.0", - "license": "MIT", - "engines": { - "node": ">=14" - } + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@fastify/accept-negotiator/-/accept-negotiator-2.0.1.tgz", + "integrity": "sha512-/c/TW2bO/v9JeEgoD/g1G5GxGeCF1Hafdf79WPmUlgYiBXummY0oX3VVq4yFkKKVBKDNlaDUYoab7g38RpPqCQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" }, "node_modules/@fastify/ajv-compiler": { - "version": "3.6.0", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-4.0.5.tgz", + "integrity": "sha512-KoWKW+MhvfTRWL4qrhUwAAZoaChluo0m0vbiJlGMt2GXvL4LVPQEjt8kSpHI3IBq5Rez8fg+XeH3cneztq+C7A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], "license": "MIT", "dependencies": { - "ajv": "^8.11.0", - "ajv-formats": "^2.1.1", - "fast-uri": "^2.0.0" + "ajv": "^8.12.0", + "ajv-formats": "^3.0.1", + "fast-uri": "^3.0.0" } }, "node_modules/@fastify/ajv-compiler/node_modules/ajv": { - "version": "8.17.1", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -1920,8 +1942,16 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@fastify/ajv-compiler/node_modules/ajv/node_modules/fast-uri": { - "version": "3.1.0", + "node_modules/@fastify/ajv-compiler/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/@fastify/cors": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/@fastify/cors/-/cors-11.2.0.tgz", + "integrity": "sha512-LbLHBuSAdGdSFZYTLVA3+Ch2t+sA6nq3Ejc6XLAKiQ6ViS2qFnvicpj0htsx03FyYeLs04HfRNBsz/a8SvbcUw==", "funding": [ { "type": "github", @@ -1932,81 +1962,163 @@ "url": "https://opencollective.com/fastify" } ], - "license": "BSD-3-Clause" - }, - "node_modules/@fastify/ajv-compiler/node_modules/json-schema-traverse": { - "version": "1.0.0", - "license": "MIT" - }, - "node_modules/@fastify/busboy": { - "version": "2.1.1", - "license": "MIT", - "engines": { - "node": ">=14" - } - }, - "node_modules/@fastify/cors": { - "version": "8.5.0", "license": "MIT", "dependencies": { - "fastify-plugin": "^4.0.0", - "mnemonist": "0.39.6" + "fastify-plugin": "^5.0.0", + "toad-cache": "^3.7.0" } }, "node_modules/@fastify/error": { - "version": "3.4.1", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@fastify/error/-/error-4.2.0.tgz", + "integrity": "sha512-RSo3sVDXfHskiBZKBPRgnQTtIqpi/7zhJOEmAxCiBcM7d0uwdGdxLlsCaLzGs8v8NnxIRlfG0N51p5yFaOentQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], "license": "MIT" }, "node_modules/@fastify/fast-json-stringify-compiler": { - "version": "4.3.0", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-5.0.3.tgz", + "integrity": "sha512-uik7yYHkLr6fxd8hJSZ8c+xF4WafPK+XzneQDPU+D10r5X19GW8lJcom2YijX2+qtFF1ENJlHXKFM9ouXNJYgQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], "license": "MIT", "dependencies": { - "fast-json-stringify": "^5.7.0" + "fast-json-stringify": "^6.0.0" } }, + "node_modules/@fastify/forwarded": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@fastify/forwarded/-/forwarded-3.0.1.tgz", + "integrity": "sha512-JqDochHFqXs3C3Ml3gOY58zM7OqO9ENqPo0UqAjAjH8L01fRZqwX9iLeX34//kiJubF7r2ZQHtBRU36vONbLlw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, "node_modules/@fastify/merge-json-schemas": { - "version": "0.1.1", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@fastify/merge-json-schemas/-/merge-json-schemas-0.2.1.tgz", + "integrity": "sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.3" + "dequal": "^2.0.3" + } + }, + "node_modules/@fastify/proxy-addr": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@fastify/proxy-addr/-/proxy-addr-5.1.0.tgz", + "integrity": "sha512-INS+6gh91cLUjB+PVHfu1UqcB76Sqtpyp7bnL+FYojhjygvOPA9ctiD/JDKsyD9Xgu4hUhCSJBPig/w7duNajw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "@fastify/forwarded": "^3.0.0", + "ipaddr.js": "^2.1.0" } }, "node_modules/@fastify/reply-from": { - "version": "9.8.0", + "version": "12.6.2", + "resolved": "https://registry.npmjs.org/@fastify/reply-from/-/reply-from-12.6.2.tgz", + "integrity": "sha512-FhMvsRJa4HMG0q0/Yi06sgwVFd/Wc8E/+RbHsqB0Q+883C66RPrS6qwZKBPje2mVzsyEb9sjq7wlyvi35zRW0A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], "license": "MIT", "dependencies": { - "@fastify/error": "^3.0.0", + "@fastify/error": "^4.0.0", "end-of-stream": "^1.4.4", - "fast-content-type-parse": "^1.1.0", - "fast-querystring": "^1.0.0", - "fastify-plugin": "^4.0.0", + "fast-content-type-parse": "^3.0.0", + "fast-querystring": "^1.1.2", + "fastify-plugin": "^5.0.1", "toad-cache": "^3.7.0", - "undici": "^5.19.1" + "undici": "^7.0.0" } }, "node_modules/@fastify/reply-from/node_modules/undici": { - "version": "5.29.0", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.25.0.tgz", + "integrity": "sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==", "license": "MIT", - "dependencies": { - "@fastify/busboy": "^2.0.0" - }, "engines": { - "node": ">=14.0" + "node": ">=20.18.1" } }, "node_modules/@fastify/send": { - "version": "2.1.0", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@fastify/send/-/send-4.1.0.tgz", + "integrity": "sha512-TMYeQLCBSy2TOFmV95hQWkiTYgC/SEx7vMdV+wnZVX4tt8VBLKzmH8vV9OzJehV0+XBfg+WxPMt5wp+JBUKsVw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], "license": "MIT", "dependencies": { - "@lukeed/ms": "^2.0.1", + "@lukeed/ms": "^2.0.2", "escape-html": "~1.0.3", "fast-decode-uri-component": "^1.0.1", - "http-errors": "2.0.0", - "mime": "^3.0.0" + "http-errors": "^2.0.0", + "mime": "^3" } }, "node_modules/@fastify/send/node_modules/mime": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", "license": "MIT", "bin": { "mime": "cli.js" @@ -2016,55 +2128,116 @@ } }, "node_modules/@fastify/static": { - "version": "7.0.4", + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@fastify/static/-/static-9.1.1.tgz", + "integrity": "sha512-LHxFea3qdwe0Pbbkh/yux7/k6nFNLGTNcbLKVYgmRDB6LdDE/8TFSO7qWZ0IzM/nF6iwR8W03oFlwe4v79R1Ow==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], "license": "MIT", "dependencies": { - "@fastify/accept-negotiator": "^1.0.0", - "@fastify/send": "^2.0.0", - "content-disposition": "^0.5.3", - "fastify-plugin": "^4.0.0", - "fastq": "^1.17.0", - "glob": "^10.3.4" + "@fastify/accept-negotiator": "^2.0.0", + "@fastify/send": "^4.0.0", + "content-disposition": "^1.0.1", + "fastify-plugin": "^5.0.0", + "fastq": "^1.17.1", + "glob": "^13.0.0" + } + }, + "node_modules/@fastify/static/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@fastify/static/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, "node_modules/@fastify/static/node_modules/glob": { - "version": "10.5.0", - "license": "ISC", + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "license": "BlueOak-1.0.0", "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" + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" }, - "bin": { - "glob": "dist/esm/bin.mjs" + "engines": { + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@fastify/static/node_modules/lru-cache": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", + "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, "node_modules/@fastify/static/node_modules/minimatch": { - "version": "9.0.5", - "license": "ISC", + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^5.0.5" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/@fastify/static/node_modules/minipass": { - "version": "7.1.2", - "license": "ISC", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" } }, + "node_modules/@fastify/static/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@floating-ui/core": { "version": "1.7.3", "license": "MIT", @@ -2703,6 +2876,8 @@ }, "node_modules/@lukeed/ms": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@lukeed/ms/-/ms-2.0.2.tgz", + "integrity": "sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA==", "license": "MIT", "engines": { "node": ">=8" @@ -2822,6 +2997,174 @@ "integrity": "sha512-dWMF8Aku4h7fh8sw5tQ2FtbqRLbIFT8FcsukpxTird49ax7oUXP+gzqxM/VdxHjfksQvzLBjLZyMdDStc5g7xA==", "license": "MIT" }, + "node_modules/@oven/bun-darwin-aarch64": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@oven/bun-darwin-aarch64/-/bun-darwin-aarch64-1.3.13.tgz", + "integrity": "sha512-qAS6Hg8Q14ckfBuqJ2Zh7gBQSVSUHeibSq4OFqBTv6DzyJuxYlr0sdYQzmYmnbPxbqobekqUDTa/4XEaqRi7vg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oven/bun-darwin-x64": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@oven/bun-darwin-x64/-/bun-darwin-x64-1.3.13.tgz", + "integrity": "sha512-kGePeDD4IN4imo+H4uLjQGZLmvyYQg+nKr2P0nt4ksXXrWA4HE+mb0/TUPHfRI127DocXQpew+fvrHuHR5mpJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oven/bun-darwin-x64-baseline": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@oven/bun-darwin-x64-baseline/-/bun-darwin-x64-baseline-1.3.13.tgz", + "integrity": "sha512-gMEQayUpmCPYaE9zkNBj9TiQqHupnhjOYcuSzxFjzIjHJBUO4VjNnrpbKVeXNs+rKHFothORDd2QKquu5paSPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oven/bun-linux-aarch64": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@oven/bun-linux-aarch64/-/bun-linux-aarch64-1.3.13.tgz", + "integrity": "sha512-NbLOJdr+RBFO1vFZ2YUFg4oVJ+2ua6zrwo4ZWRs0jKKcGJWtbY2wY5uz+i0PkwH6b9HYaYDgVTzE4ev06ncYZw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-linux-aarch64-musl": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@oven/bun-linux-aarch64-musl/-/bun-linux-aarch64-musl-1.3.13.tgz", + "integrity": "sha512-UV9EE18VE5aRhWtV2L6MTAGGn3slhJJ2OW/m+FJM15maHm0qf1V7TaZY0FovxhdQRvnklSiQ7Ntv0H5TUX4w0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-linux-x64": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@oven/bun-linux-x64/-/bun-linux-x64-1.3.13.tgz", + "integrity": "sha512-UwttIUXoe9fS+40OcjoaRHgZw+HCPFqBVWEXkXqAJ3W7wA0XPZrWsoMAD9sGh3TaLqrwdiMo5xPogwpXhOtVXA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-linux-x64-baseline": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@oven/bun-linux-x64-baseline/-/bun-linux-x64-baseline-1.3.13.tgz", + "integrity": "sha512-fOi4ziKzgJG4UrrNd4AicBs6Fu9GY5xOqg+9tC76nuZNDAdSh6++kzab6TNi1Ck0Yzq6zIBIdGit6/0uSbBn8A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-linux-x64-musl": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@oven/bun-linux-x64-musl/-/bun-linux-x64-musl-1.3.13.tgz", + "integrity": "sha512-+VHhE44kEjCXcTFHyc81zfTxL9+vzh9RqIh7gM1iWNhxpctD9kzntbUkP3UTFTwwNjoou1o8VRyxQafvc4OepA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-linux-x64-musl-baseline": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@oven/bun-linux-x64-musl-baseline/-/bun-linux-x64-musl-baseline-1.3.13.tgz", + "integrity": "sha512-fqBKuiiWLEu2dVkowZaXgKS98xfrvBqivdoxRtRP3eINcpI1dcelGbsOz+Xphn7tbGAuBiE1/0AelvvvdqS9rg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-windows-aarch64": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@oven/bun-windows-aarch64/-/bun-windows-aarch64-1.3.13.tgz", + "integrity": "sha512-+EvdRWRCRg95Xea4M2lqSJFTjzQBTJDQTMlbG8bmwFkVTN16MdmSH7xhfxVQWUOyZBLEpIwuNFIlBBxVCwSUyQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@oven/bun-windows-x64": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@oven/bun-windows-x64/-/bun-windows-x64-1.3.13.tgz", + "integrity": "sha512-vqDEFX63ZZQF3YstPSpPD+RxNm5AILPdUuuKpNwsj7ld4NjhdHUYkAmLXDtKNWt9JMRL10bop//W8faY/LV+RQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@oven/bun-windows-x64-baseline": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@oven/bun-windows-x64-baseline/-/bun-windows-x64-baseline-1.3.13.tgz", + "integrity": "sha512-6gy4hhQSjq/T/S9hC9m3NxY0RY+9Ww+XNlB+8koIMTsMSYEjk7Ho+hFHQz1Bn4W61Ub7Vykufg+jgDgPfa2GFA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@pinojs/redact": { "version": "0.4.0", "license": "MIT" @@ -3559,7 +3902,9 @@ } }, "node_modules/@tauri-apps/cli": { - "version": "2.9.4", + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.10.1.tgz", + "integrity": "sha512-jQNGF/5quwORdZSSLtTluyKQ+o6SMa/AUICfhf4egCGFdMHqWssApVgYSbg+jmrZoc8e1DscNvjTnXtlHLS11g==", "dev": true, "license": "Apache-2.0 OR MIT", "bin": { @@ -3573,21 +3918,40 @@ "url": "https://opencollective.com/tauri" }, "optionalDependencies": { - "@tauri-apps/cli-darwin-arm64": "2.9.4", - "@tauri-apps/cli-darwin-x64": "2.9.4", - "@tauri-apps/cli-linux-arm-gnueabihf": "2.9.4", - "@tauri-apps/cli-linux-arm64-gnu": "2.9.4", - "@tauri-apps/cli-linux-arm64-musl": "2.9.4", - "@tauri-apps/cli-linux-riscv64-gnu": "2.9.4", - "@tauri-apps/cli-linux-x64-gnu": "2.9.4", - "@tauri-apps/cli-linux-x64-musl": "2.9.4", - "@tauri-apps/cli-win32-arm64-msvc": "2.9.4", - "@tauri-apps/cli-win32-ia32-msvc": "2.9.4", - "@tauri-apps/cli-win32-x64-msvc": "2.9.4" + "@tauri-apps/cli-darwin-arm64": "2.10.1", + "@tauri-apps/cli-darwin-x64": "2.10.1", + "@tauri-apps/cli-linux-arm-gnueabihf": "2.10.1", + "@tauri-apps/cli-linux-arm64-gnu": "2.10.1", + "@tauri-apps/cli-linux-arm64-musl": "2.10.1", + "@tauri-apps/cli-linux-riscv64-gnu": "2.10.1", + "@tauri-apps/cli-linux-x64-gnu": "2.10.1", + "@tauri-apps/cli-linux-x64-musl": "2.10.1", + "@tauri-apps/cli-win32-arm64-msvc": "2.10.1", + "@tauri-apps/cli-win32-ia32-msvc": "2.10.1", + "@tauri-apps/cli-win32-x64-msvc": "2.10.1" + } + }, + "node_modules/@tauri-apps/cli-darwin-arm64": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.10.1.tgz", + "integrity": "sha512-Z2OjCXiZ+fbYZy7PmP3WRnOpM9+Fy+oonKDEmUE6MwN4IGaYqgceTjwHucc/kEEYZos5GICve35f7ZiizgqEnQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" } }, "node_modules/@tauri-apps/cli-darwin-x64": { - "version": "2.9.4", + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.10.1.tgz", + "integrity": "sha512-V/irQVvjPMGOTQqNj55PnQPVuH4VJP8vZCN7ajnj+ZS8Kom1tEM2hR3qbbIRoS3dBKs5mbG8yg1WC+97dq17Pw==", "cpu": [ "x64" ], @@ -3601,10 +3965,161 @@ "node": ">= 10" } }, + "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.10.1.tgz", + "integrity": "sha512-Hyzwsb4VnCWKGfTw+wSt15Z2pLw2f0JdFBfq2vHBOBhvg7oi6uhKiF87hmbXOBXUZaGkyRDkCHsdzJcIfoJC2w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-gnu": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.10.1.tgz", + "integrity": "sha512-OyOYs2t5GkBIvyWjA1+h4CZxTcdz1OZPCWAPz5DYEfB0cnWHERTnQ/SLayQzncrT0kwRoSfSz9KxenkyJoTelA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-musl": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.10.1.tgz", + "integrity": "sha512-MIj78PDDGjkg3NqGptDOGgfXks7SYJwhiMh8SBoZS+vfdz7yP5jN18bNaLnDhsVIPARcAhE1TlsZe/8Yxo2zqg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-riscv64-gnu": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.10.1.tgz", + "integrity": "sha512-X0lvOVUg8PCVaoEtEAnpxmnkwlE1gcMDTqfhbefICKDnOTJ5Est3qL0SrWxizDackIOKBcvtpejrSiVpuJI1kw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-gnu": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.10.1.tgz", + "integrity": "sha512-2/12bEzsJS9fAKybxgicCDFxYD1WEI9kO+tlDwX5znWG2GwMBaiWcmhGlZ8fi+DMe9CXlcVarMTYc0L3REIRxw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-musl": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.10.1.tgz", + "integrity": "sha512-Y8J0ZzswPz50UcGOFuXGEMrxbjwKSPgXftx5qnkuMs2rmwQB5ssvLb6tn54wDSYxe7S6vlLob9vt0VKuNOaCIQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-arm64-msvc": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.10.1.tgz", + "integrity": "sha512-iSt5B86jHYAPJa/IlYw++SXtFPGnWtFJriHn7X0NFBVunF6zu9+/zOn8OgqIWSl8RgzhLGXQEEtGBdR4wzpVgg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-ia32-msvc": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.10.1.tgz", + "integrity": "sha512-gXyxgEzsFegmnWywYU5pEBURkcFN/Oo45EAwvZrHMh+zUSEAvO5E8TXsgPADYm31d1u7OQU3O3HsYfVBf2moHw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@tauri-apps/cli-win32-x64-msvc": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.9.4.tgz", - "integrity": "sha512-EdYd4c9wGvtPB95kqtEyY+bUR+k4kRw3IA30mAQ1jPH6z57AftT8q84qwv0RDp6kkEqOBKxeInKfqi4BESYuqg==", + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.10.1.tgz", + "integrity": "sha512-6Cn7YpPFwzChy0ERz6djKEmUehWrYlM+xTaNzGPgZocw3BD7OfwfWHKVWxXzdjEW2KfKkHddfdxK1XXTYqBRLg==", "cpu": [ "x64" ], @@ -3677,7 +4192,6 @@ "version": "7.20.5", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", @@ -3779,7 +4293,6 @@ "version": "22.19.0", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -3854,7 +4367,6 @@ "integrity": "sha512-MCbrb508JZHqe7bUibmZj/lyojdhLRnfkmyXnkrCM2zVrjTgL89U8UEfInpKTvPeTnxsw2hmyZxnhsdNR6yhwg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "cac": "^6.7.14", "colorette": "^2.0.20", @@ -3937,7 +4449,6 @@ "version": "6.12.6", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -3950,7 +4461,9 @@ } }, "node_modules/ajv-formats": { - "version": "2.1.1", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -3965,7 +4478,9 @@ } }, "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.17.1", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -3978,22 +4493,10 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ajv-formats/node_modules/fast-uri": { - "version": "3.1.0", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, "node_modules/ajv-formats/node_modules/json-schema-traverse": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "license": "MIT" }, "node_modules/ajv-keywords": { @@ -4140,6 +4643,7 @@ "version": "5.3.2", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "archiver-utils": "^2.1.0", "async": "^3.2.4", @@ -4157,6 +4661,7 @@ "version": "2.1.0", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "glob": "^7.1.4", "graceful-fs": "^4.2.0", @@ -4177,6 +4682,7 @@ "version": "2.3.8", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -4190,12 +4696,14 @@ "node_modules/archiver-utils/node_modules/safe-buffer": { "version": "5.1.2", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/archiver-utils/node_modules/string_decoder": { "version": "1.1.1", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -4363,10 +4871,22 @@ } }, "node_modules/avvio": { - "version": "8.4.0", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/avvio/-/avvio-9.2.0.tgz", + "integrity": "sha512-2t/sy01ArdHHE0vRH5Hsay+RtCZt3dLPji7W7/MMOCEgze5b7SNDC4j5H6FnVgPkI1MTNFGzHdHrVXDDl7QSSQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], "license": "MIT", "dependencies": { - "@fastify/error": "^3.3.0", + "@fastify/error": "^4.0.0", "fastq": "^1.17.1" } }, @@ -4509,6 +5029,7 @@ "version": "4.1.0", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -4572,7 +5093,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -4704,6 +5224,41 @@ "node": ">= 10.0.0" } }, + "node_modules/bun": { + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/bun/-/bun-1.3.13.tgz", + "integrity": "sha512-b9T4xZ8KqCHs4+TkHJv540LG1B8OD7noKu0Qaizusx3jFtMDHY6osNqgbaOlwW2B8RB2AKzz+sjzlGKIGxIjZw==", + "cpu": [ + "arm64", + "x64" + ], + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "os": [ + "darwin", + "linux", + "win32" + ], + "bin": { + "bun": "bin/bun.exe", + "bunx": "bin/bunx.exe" + }, + "optionalDependencies": { + "@oven/bun-darwin-aarch64": "1.3.13", + "@oven/bun-darwin-x64": "1.3.13", + "@oven/bun-darwin-x64-baseline": "1.3.13", + "@oven/bun-linux-aarch64": "1.3.13", + "@oven/bun-linux-aarch64-musl": "1.3.13", + "@oven/bun-linux-x64": "1.3.13", + "@oven/bun-linux-x64-baseline": "1.3.13", + "@oven/bun-linux-x64-musl": "1.3.13", + "@oven/bun-linux-x64-musl-baseline": "1.3.13", + "@oven/bun-windows-aarch64": "1.3.13", + "@oven/bun-windows-x64": "1.3.13", + "@oven/bun-windows-x64-baseline": "1.3.13" + } + }, "node_modules/cac": { "version": "6.7.14", "dev": true, @@ -5063,6 +5618,7 @@ "version": "4.1.2", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "buffer-crc32": "^0.2.13", "crc32-stream": "^4.0.2", @@ -5139,13 +5695,16 @@ } }, "node_modules/content-disposition": { - "version": "0.5.4", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/convert-source-map": { @@ -5154,10 +5713,16 @@ "license": "MIT" }, "node_modules/cookie": { - "version": "0.7.2", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/core-js-compat": { @@ -5192,6 +5757,7 @@ "version": "1.2.2", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "crc32": "bin/crc32.njs" }, @@ -5203,6 +5769,7 @@ "version": "4.0.3", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "crc-32": "^1.2.0", "readable-stream": "^3.4.0" @@ -5474,6 +6041,8 @@ }, "node_modules/depd": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -5568,7 +6137,6 @@ "version": "24.13.3", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "app-builder-lib": "24.13.3", "builder-util": "24.13.1", @@ -5735,6 +6303,7 @@ "version": "24.13.3", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "app-builder-lib": "24.13.3", "archiver": "^5.3.1", @@ -5746,6 +6315,7 @@ "version": "10.1.0", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -5759,6 +6329,7 @@ "version": "6.2.0", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "universalify": "^2.0.0" }, @@ -5770,6 +6341,7 @@ "version": "2.0.1", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">= 10.0.0" } @@ -6106,6 +6678,8 @@ }, "node_modules/escape-html": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", "license": "MIT" }, "node_modules/escape-string-regexp": { @@ -6170,7 +6744,19 @@ "optional": true }, "node_modules/fast-content-type-parse": { - "version": "1.1.0", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-3.0.0.tgz", + "integrity": "sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], "license": "MIT" }, "node_modules/fast-decode-uri-component": { @@ -6217,20 +6803,33 @@ "license": "MIT" }, "node_modules/fast-json-stringify": { - "version": "5.16.1", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-6.3.0.tgz", + "integrity": "sha512-oRCntNDY/329HJPlmdNLIdogNtt6Vyjb1WuT01Soss3slIdyUp8kAcDU3saQTOquEK8KFVfwIIF7FebxUAu+yA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], "license": "MIT", "dependencies": { - "@fastify/merge-json-schemas": "^0.1.0", - "ajv": "^8.10.0", + "@fastify/merge-json-schemas": "^0.2.0", + "ajv": "^8.12.0", "ajv-formats": "^3.0.1", - "fast-deep-equal": "^3.1.3", - "fast-uri": "^2.1.0", - "json-schema-ref-resolver": "^1.0.1", + "fast-uri": "^3.0.0", + "json-schema-ref-resolver": "^3.0.0", "rfdc": "^1.2.0" } }, "node_modules/fast-json-stringify/node_modules/ajv": { - "version": "8.17.1", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -6243,23 +6842,23 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/fast-json-stringify/node_modules/ajv-formats": { - "version": "3.0.1", + "node_modules/fast-json-stringify/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/fast-querystring": { + "version": "1.1.2", "license": "MIT", "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } + "fast-decode-uri-component": "^1.0.1" } }, - "node_modules/fast-json-stringify/node_modules/ajv/node_modules/fast-uri": { + "node_modules/fast-uri": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", "funding": [ { "type": "github", @@ -6272,23 +6871,10 @@ ], "license": "BSD-3-Clause" }, - "node_modules/fast-json-stringify/node_modules/json-schema-traverse": { - "version": "1.0.0", - "license": "MIT" - }, - "node_modules/fast-querystring": { - "version": "1.1.2", - "license": "MIT", - "dependencies": { - "fast-decode-uri-component": "^1.0.1" - } - }, - "node_modules/fast-uri": { - "version": "2.4.0", - "license": "MIT" - }, "node_modules/fastify": { - "version": "4.29.1", + "version": "5.8.5", + "resolved": "https://registry.npmjs.org/fastify/-/fastify-5.8.5.tgz", + "integrity": "sha512-Yqptv59pQzPgQUSIm87hMqHJmdkb1+GPxdE6vW6FRyVE9G86mt7rOghitiU4JHRaTyDUk9pfeKmDeu70lAwM4Q==", "funding": [ { "type": "github", @@ -6301,26 +6887,37 @@ ], "license": "MIT", "dependencies": { - "@fastify/ajv-compiler": "^3.5.0", - "@fastify/error": "^3.4.0", - "@fastify/fast-json-stringify-compiler": "^4.3.0", + "@fastify/ajv-compiler": "^4.0.5", + "@fastify/error": "^4.0.0", + "@fastify/fast-json-stringify-compiler": "^5.0.0", + "@fastify/proxy-addr": "^5.0.0", "abstract-logging": "^2.0.1", - "avvio": "^8.3.0", - "fast-content-type-parse": "^1.1.0", - "fast-json-stringify": "^5.8.0", - "find-my-way": "^8.0.0", - "light-my-request": "^5.11.0", - "pino": "^9.0.0", - "process-warning": "^3.0.0", - "proxy-addr": "^2.0.7", - "rfdc": "^1.3.0", - "secure-json-parse": "^2.7.0", - "semver": "^7.5.4", - "toad-cache": "^3.3.0" + "avvio": "^9.0.0", + "fast-json-stringify": "^6.0.0", + "find-my-way": "^9.0.0", + "light-my-request": "^6.0.0", + "pino": "^9.14.0 || ^10.1.0", + "process-warning": "^5.0.0", + "rfdc": "^1.3.1", + "secure-json-parse": "^4.0.0", + "semver": "^7.6.0", + "toad-cache": "^3.7.0" } }, "node_modules/fastify-plugin": { - "version": "4.5.1", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-5.1.0.tgz", + "integrity": "sha512-FAIDA8eovSt5qcDgcBvDuX/v0Cjz0ohGhENZ/wpc3y+oZCY2afZ9Baqql3g/lC+OHRnciQol4ww7tuthOb9idw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], "license": "MIT" }, "node_modules/fastify/node_modules/semver": { @@ -6388,15 +6985,17 @@ } }, "node_modules/find-my-way": { - "version": "8.2.2", + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-9.5.0.tgz", + "integrity": "sha512-VW2RfnmscZO5KgBY5XVyKREMW5nMZcxDy+buTOsL+zIPnBlbKm+00sgzoQzq1EVh4aALZLfKdwv6atBGcjvjrQ==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "fast-querystring": "^1.0.0", - "safe-regex2": "^3.1.0" + "safe-regex2": "^5.0.0" }, "engines": { - "node": ">=14" + "node": ">=20" } }, "node_modules/find-up": { @@ -6465,13 +7064,6 @@ "node": ">=12.20.0" } }, - "node_modules/forwarded": { - "version": "0.2.0", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/fraction.js": { "version": "4.3.7", "dev": true, @@ -6487,7 +7079,8 @@ "node_modules/fs-constants": { "version": "1.0.0", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/fs-extra": { "version": "8.1.0", @@ -7085,17 +7678,23 @@ "license": "BSD-2-Clause" }, "node_modules/http-errors": { - "version": "2.0.0", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/http-proxy-agent": { @@ -7224,10 +7823,12 @@ } }, "node_modules/ipaddr.js": { - "version": "1.9.1", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.3.0.tgz", + "integrity": "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==", "license": "MIT", "engines": { - "node": ">= 0.10" + "node": ">= 10" } }, "node_modules/is-array-buffer": { @@ -7704,7 +8305,8 @@ "node_modules/isarray": { "version": "1.0.0", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/isbinaryfile": { "version": "5.0.6", @@ -7754,7 +8356,6 @@ "version": "1.21.7", "dev": true, "license": "MIT", - "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -7806,10 +8407,22 @@ "license": "(AFL-2.1 OR BSD-3-Clause)" }, "node_modules/json-schema-ref-resolver": { - "version": "1.0.1", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-schema-ref-resolver/-/json-schema-ref-resolver-3.0.0.tgz", + "integrity": "sha512-hOrZIVL5jyYFjzk7+y7n5JDzGlU8rfWDuYyHwGa2WA8/pcmMHezp2xsVwxrebD/Q9t8Nc5DboieySDpCp4WG4A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.3" + "dequal": "^2.0.3" } }, "node_modules/json-schema-traverse": { @@ -7886,6 +8499,7 @@ "version": "1.0.1", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "readable-stream": "^2.0.5" }, @@ -7897,6 +8511,7 @@ "version": "2.3.8", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -7910,12 +8525,14 @@ "node_modules/lazystream/node_modules/safe-buffer": { "version": "5.1.2", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/lazystream/node_modules/string_decoder": { "version": "1.1.1", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -7931,14 +8548,42 @@ } }, "node_modules/light-my-request": { - "version": "5.14.0", + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-6.6.0.tgz", + "integrity": "sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], "license": "BSD-3-Clause", "dependencies": { - "cookie": "^0.7.0", - "process-warning": "^3.0.0", - "set-cookie-parser": "^2.4.1" + "cookie": "^1.0.1", + "process-warning": "^4.0.0", + "set-cookie-parser": "^2.6.0" } }, + "node_modules/light-my-request/node_modules/process-warning": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-4.0.1.tgz", + "integrity": "sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, "node_modules/lilconfig": { "version": "3.1.3", "dev": true, @@ -7980,22 +8625,26 @@ "node_modules/lodash.defaults": { "version": "4.2.0", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/lodash.difference": { "version": "4.5.0", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/lodash.flatten": { "version": "4.4.0", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/lodash.isplainobject": { "version": "4.0.6", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/lodash.sortby": { "version": "4.7.0", @@ -8007,7 +8656,8 @@ "node_modules/lodash.union": { "version": "4.6.0", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/lowercase-keys": { "version": "2.0.0", @@ -8323,13 +8973,6 @@ "node": ">=10" } }, - "node_modules/mnemonist": { - "version": "0.39.6", - "license": "MIT", - "dependencies": { - "obliterator": "^2.0.1" - } - }, "node_modules/monaco-editor": { "version": "0.52.2", "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.52.2.tgz", @@ -8505,10 +9148,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/obliterator": { - "version": "2.0.5", - "license": "MIT" - }, "node_modules/on-exit-leak-free": { "version": "2.1.2", "license": "MIT", @@ -8732,20 +9371,6 @@ "version": "7.0.0", "license": "MIT" }, - "node_modules/pino/node_modules/process-warning": { - "version": "5.0.0", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "MIT" - }, "node_modules/pirates": { "version": "4.0.7", "dev": true, @@ -8811,7 +9436,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -8959,10 +9583,23 @@ "node_modules/process-nextick-args": { "version": "2.0.1", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/process-warning": { - "version": "3.0.0", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", + "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], "license": "MIT" }, "node_modules/progress": { @@ -8993,17 +9630,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/pump": { "version": "3.0.3", "dev": true, @@ -9208,6 +9834,7 @@ "version": "3.6.2", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -9221,6 +9848,7 @@ "version": "1.1.3", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "minimatch": "^5.1.0" } @@ -9425,7 +10053,9 @@ } }, "node_modules/ret": { - "version": "0.4.3", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.5.0.tgz", + "integrity": "sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==", "license": "MIT", "engines": { "node": ">=10" @@ -9449,6 +10079,8 @@ }, "node_modules/rfdc": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "license": "MIT" }, "node_modules/rimraf": { @@ -9523,7 +10155,6 @@ "version": "4.52.5", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -9670,10 +10301,25 @@ } }, "node_modules/safe-regex2": { - "version": "3.1.0", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-5.1.1.tgz", + "integrity": "sha512-mOSBvHGDZMuIEZMdOz/aCEYDCv0E7nfcNsIhUF+/P+xC7Hyf3FkvymqgPbg9D1EdSGu+uKbJgy09K/RKKc7kJA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], "license": "MIT", "dependencies": { - "ret": "~0.4.0" + "ret": "~0.5.0" + }, + "bin": { + "safe-regex2": "bin/safe-regex2.js" } }, "node_modules/safe-stable-stringify": { @@ -9702,7 +10348,19 @@ "license": "BlueOak-1.0.0" }, "node_modules/secure-json-parse": { - "version": "2.7.0", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-4.1.0.tgz", + "integrity": "sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], "license": "BSD-3-Clause" }, "node_modules/semver": { @@ -9747,7 +10405,6 @@ "node_modules/seroval": { "version": "1.3.2", "license": "MIT", - "peer": true, "engines": { "node": ">=10" } @@ -9768,6 +10425,8 @@ }, "node_modules/set-cookie-parser": { "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", "license": "MIT" }, "node_modules/set-function-length": { @@ -9821,6 +10480,8 @@ }, "node_modules/setprototypeof": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, "node_modules/sharp": { @@ -10071,7 +10732,6 @@ "node_modules/solid-js": { "version": "1.9.10", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.1.0", "seroval": "~1.3.0", @@ -10188,7 +10848,9 @@ } }, "node_modules/statuses": { - "version": "2.0.1", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -10212,6 +10874,7 @@ "version": "1.3.0", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "safe-buffer": "~5.2.0" } @@ -10545,6 +11208,7 @@ "version": "2.2.0", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -10737,7 +11401,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -10788,6 +11451,8 @@ }, "node_modules/toidentifier": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "license": "MIT", "engines": { "node": ">=0.6" @@ -10987,7 +11652,6 @@ "version": "5.9.3", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -11057,10 +11721,12 @@ } }, "node_modules/undici": { - "version": "6.22.0", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.1.0.tgz", + "integrity": "sha512-E9MkTS4xXLnRPYqxH2e6Hr2/49e7WFDKczKcCaFH4VaZs2iNvHMqeIkyUAD9vM8kujy9TjVrRlQ5KkdEJxB2pw==", "license": "MIT", "engines": { - "node": ">=18.17" + "node": ">=22.19.0" } }, "node_modules/undici-types": { @@ -11335,7 +12001,6 @@ "version": "5.4.21", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -11820,7 +12485,6 @@ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -11839,23 +12503,6 @@ "dev": true, "license": "MIT" }, - "node_modules/workbox-build/node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, "node_modules/workbox-build/node_modules/fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -12015,7 +12662,6 @@ "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "rollup": "dist/bin/rollup" }, @@ -12304,6 +12950,7 @@ "version": "4.1.1", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "archiver-utils": "^3.0.4", "compress-commons": "^4.1.2", @@ -12317,6 +12964,7 @@ "version": "3.0.4", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "glob": "^7.2.3", "graceful-fs": "^4.2.0", @@ -12336,7 +12984,6 @@ "node_modules/zod": { "version": "3.25.76", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -12391,16 +13038,16 @@ "version": "0.14.0", "license": "MIT", "dependencies": { - "@fastify/cors": "^8.5.0", - "@fastify/reply-from": "^9.8.0", - "@fastify/static": "^7.0.4", + "@fastify/cors": "^11.2.0", + "@fastify/reply-from": "^12.6.2", + "@fastify/static": "^9.1.1", "commander": "^12.1.0", - "fastify": "^4.28.1", + "fastify": "^5.8.5", "fuzzysort": "^2.0.4", "node-forge": "^1.3.3", "openai": "^6.27.0", "pino": "^9.4.0", - "undici": "^6.19.8", + "undici": "^8.1.0", "yaml": "^2.4.2", "yauzl": "^2.10.0", "zod": "^3.23.8" @@ -12411,6 +13058,7 @@ "devDependencies": { "@types/node-forge": "^1.3.14", "@types/yauzl": "^2.10.0", + "bun": "^1.3.13", "cross-env": "^7.0.3", "ts-node": "^10.9.2", "tsx": "^4.20.6", @@ -12433,7 +13081,7 @@ "version": "0.14.0", "license": "MIT", "devDependencies": { - "@tauri-apps/cli": "^2.9.4" + "@tauri-apps/cli": "^2.10.1" } }, "packages/ui": { diff --git a/packages/electron-app/electron/main/main.ts b/packages/electron-app/electron/main/main.ts index 4cdc324e..df6fff83 100644 --- a/packages/electron-app/electron/main/main.ts +++ b/packages/electron-app/electron/main/main.ts @@ -118,6 +118,8 @@ function loadLoadingScreen(window: BrowserWindow) { loader.catch((error) => { console.error("[cli] failed to load loading screen:", error) }) + + return loader } function getAllowedRendererOrigins(window?: BrowserWindow | null): string[] { @@ -292,7 +294,7 @@ function createWindow() { showingLoadingScreen = true currentCliUrl = null clearWindowAllowedOrigin(window) - loadLoadingScreen(window) + const loadingReady = loadLoadingScreen(window) if (process.env.NODE_ENV === "development") { window.webContents.openDevTools({ mode: "detach" }) @@ -311,11 +313,7 @@ function createWindow() { showingLoadingScreen = false }) - if (pendingCliUrl) { - const url = pendingCliUrl - pendingCliUrl = null - startCliPreload(url) - } + return loadingReady } function showLoadingScreen(force = false) { @@ -622,7 +620,8 @@ app.whenReady().then(() => { // ignore } - startCli() + const loadingReady = createWindow() + ;(mainWindow as BrowserWindow & { __codenomadOpenRemoteWindow?: typeof openRemoteWindow }).__codenomadOpenRemoteWindow = openRemoteWindow if (isMac) { session.defaultSession.setSpellCheckerEnabled(false) @@ -639,8 +638,11 @@ app.whenReady().then(() => { } } - createWindow() - ;(mainWindow as BrowserWindow & { __codenomadOpenRemoteWindow?: typeof openRemoteWindow }).__codenomadOpenRemoteWindow = openRemoteWindow + void loadingReady.finally(() => { + setTimeout(() => { + void startCli() + }, 0) + }) app.on("certificate-error", (event, _webContents, url, error, _certificate, callback) => { if (isInsecureOriginAllowed(url)) { diff --git a/packages/electron-app/electron/main/process-manager.ts b/packages/electron-app/electron/main/process-manager.ts index 9cb4a041..6d0d36cc 100644 --- a/packages/electron-app/electron/main/process-manager.ts +++ b/packages/electron-app/electron/main/process-manager.ts @@ -38,7 +38,7 @@ interface StartOptions { interface CliEntryResolution { entry: string - runner: "node" | "tsx" + runner: "node" | "tsx" | "standalone" runnerPath?: string } @@ -148,15 +148,15 @@ export class CliProcessManager extends EventEmitter { const listeningMode = this.resolveListeningMode() const host = resolveHostForMode(listeningMode) const args = this.buildCliArgs(options, host) + const cliEntry = this.resolveCliEntry(options) let child: ManagedChild - if (this.shouldUsePackagedShellSupervisor(options)) { - const runtimePath = this.resolveShellNodeCommand() - const entryPath = this.resolveBundledProdEntry() + if (this.shouldUsePackagedShellSupervisor(options, cliEntry)) { const supervisorPath = this.resolveCliSupervisorPath() const shellEnv = supportsUserShell() ? getUserShellEnv() : { ...process.env } - const shellCommand = buildUserShellCommand(`exec ${this.buildExecutableCommand(runtimePath, [entryPath, ...args])}`) + const shellTarget = cliEntry.runner === "standalone" ? this.buildExecutableCommand(cliEntry.entry, args) : this.buildCommand(cliEntry, args) + const shellCommand = buildUserShellCommand(`exec ${shellTarget}`) const supervisorPayload = JSON.stringify({ command: shellCommand.command, args: shellCommand.args, @@ -164,28 +164,33 @@ export class CliProcessManager extends EventEmitter { }) console.info( - `[cli] launching CodeNomad CLI (${options.dev ? "dev" : "prod"}) via utility supervisor using node at ${runtimePath} (host=${host})`, + `[cli] launching CodeNomad CLI (${options.dev ? "dev" : "prod"}) via utility supervisor using ${cliEntry.runner} at ${cliEntry.entry} (host=${host})`, ) console.info(`[cli] utility supervisor: ${supervisorPath}`) console.info(`[cli] shell command: ${shellCommand.command} ${shellCommand.args.join(" ")}`) child = utilityProcess.fork(supervisorPath, [supervisorPayload], { - env: shellEnv, + env: cliEntry.runner === "standalone" ? shellEnv : { ...shellEnv, ELECTRON_RUN_AS_NODE: "1" }, stdio: "pipe", serviceName: "CodeNomad CLI Supervisor", }) this.childLaunchMode = "utility" } else { - const cliEntry = this.resolveCliEntry(options) console.info( `[cli] launching CodeNomad CLI (${options.dev ? "dev" : "prod"}) using ${cliEntry.runner} at ${cliEntry.entry} (host=${host})`, ) const env = supportsUserShell() ? getUserShellEnv() : { ...process.env } - env.ELECTRON_RUN_AS_NODE = "1" + if (cliEntry.runner !== "standalone") { + env.ELECTRON_RUN_AS_NODE = "1" + } const spawnDetails = supportsUserShell() - ? buildUserShellCommand(`ELECTRON_RUN_AS_NODE=1 exec ${this.buildCommand(cliEntry, args)}`) + ? buildUserShellCommand( + `${cliEntry.runner === "standalone" ? "" : "ELECTRON_RUN_AS_NODE=1 "}exec ${ + cliEntry.runner === "standalone" ? this.buildExecutableCommand(cliEntry.entry, args) : this.buildCommand(cliEntry, args) + }`, + ) : this.buildDirectSpawn(cliEntry, args) const detached = process.platform !== "win32" @@ -563,6 +568,10 @@ export class CliProcessManager extends EventEmitter { } private buildCommand(cliEntry: CliEntryResolution, args: string[]): string { + if (cliEntry.runner === "standalone") { + return this.buildExecutableCommand(cliEntry.entry, args) + } + const parts = [JSON.stringify(process.execPath)] if (cliEntry.runner === "tsx" && cliEntry.runnerPath) { parts.push(JSON.stringify(cliEntry.runnerPath)) @@ -577,6 +586,10 @@ export class CliProcessManager extends EventEmitter { } private buildDirectSpawn(cliEntry: CliEntryResolution, args: string[]) { + if (cliEntry.runner === "standalone") { + return { command: cliEntry.entry, args } + } + if (cliEntry.runner === "tsx") { return { command: process.execPath, args: [cliEntry.runnerPath!, cliEntry.entry, ...args] } } @@ -593,9 +606,8 @@ export class CliProcessManager extends EventEmitter { const devEntry = this.resolveDevEntry() return { entry: devEntry, runner: "tsx", runnerPath: tsxPath } } - - const distEntry = this.resolveProdEntry() - return { entry: distEntry, runner: "node" } + + return { entry: this.resolveStandaloneProdEntry(), runner: "standalone" } } private resolveTsx(): string | null { @@ -635,20 +647,25 @@ export class CliProcessManager extends EventEmitter { return entry } - private resolveProdEntry(): string { - try { - const entry = nodeRequire.resolve("@neuralnomads/codenomad/dist/bin.js") - if (existsSync(entry)) { - return entry + private resolveStandaloneProdEntry(): string { + const executableName = process.platform === "win32" ? "codenomad-server.exe" : "codenomad-server" + const candidates = [ + path.join(process.resourcesPath, "server", "dist", executableName), + path.join(mainDirname, "../resources/server/dist", executableName), + path.resolve(process.cwd(), "..", "server", "dist", executableName), + ] + + for (const candidate of candidates) { + if (existsSync(candidate)) { + return candidate } - } catch { - // fall through to error below } - throw new Error("Unable to locate CodeNomad CLI build (dist/bin.js). Run npm run build --workspace @neuralnomads/codenomad.") + + throw new Error(`Unable to locate standalone CodeNomad server executable (${executableName}). Run npm run build:standalone --workspace @neuralnomads/codenomad.`) } - private shouldUsePackagedShellSupervisor(options: StartOptions): boolean { - return !options.dev && app.isPackaged && process.platform === "darwin" + private shouldUsePackagedShellSupervisor(options: StartOptions, cliEntry: CliEntryResolution): boolean { + return !options.dev && app.isPackaged && process.platform === "darwin" && cliEntry.runner !== "standalone" } private resolveCliSupervisorPath(): string { @@ -666,26 +683,6 @@ export class CliProcessManager extends EventEmitter { throw new Error("Unable to locate CodeNomad CLI supervisor script.") } - private resolveShellNodeCommand(): string { - const configured = process.env.NODE_BINARY?.trim() - return configured && configured.length > 0 ? configured : "node" - } - - private resolveBundledProdEntry(): string { - const candidates = [ - path.join(process.resourcesPath, "server", "dist", "bin.js"), - path.join(mainDirname, "../resources/server/dist/bin.js"), - ] - - for (const candidate of candidates) { - if (existsSync(candidate)) { - return candidate - } - } - - throw new Error("Unable to locate bundled CodeNomad CLI build in app resources.") - } - private describeUtilityProcessError(error: unknown): string { if (error instanceof Error && error.message) { return error.message diff --git a/packages/electron-app/scripts/build.js b/packages/electron-app/scripts/build.js index 636170d8..3651c3bd 100644 --- a/packages/electron-app/scripts/build.js +++ b/packages/electron-app/scripts/build.js @@ -1,7 +1,7 @@ #!/usr/bin/env node import { spawn } from "child_process" -import { existsSync } from "fs" +import { existsSync, readFileSync } from "fs" import path, { join } from "path" import { fileURLToPath } from "url" @@ -14,6 +14,46 @@ const npxCmd = process.platform === "win32" ? "npx.cmd" : "npx" const nodeModulesPath = join(appDir, "node_modules") const workspaceNodeModulesPath = join(workspaceRoot, "node_modules") +function getPlatformEsbuildPackage() { + const platformKey = `${process.platform}-${process.arch}` + const platformPackages = { + "linux-x64": "@esbuild/linux-x64", + "linux-arm64": "@esbuild/linux-arm64", + "darwin-arm64": "@esbuild/darwin-arm64", + "darwin-x64": "@esbuild/darwin-x64", + "win32-arm64": "@esbuild/win32-arm64", + "win32-x64": "@esbuild/win32-x64", + } + + return platformPackages[platformKey] ?? null +} + +async function ensureEsbuildPlatformBinary() { + const pkgName = getPlatformEsbuildPackage() + if (!pkgName) { + return + } + + const platformPackagePath = join(workspaceNodeModulesPath, ...pkgName.split("/")) + if (existsSync(platformPackagePath)) { + return + } + + let esbuildVersion = "" + try { + esbuildVersion = JSON.parse(readFileSync(join(workspaceNodeModulesPath, "esbuild", "package.json"), "utf-8")).version ?? "" + } catch { + // leave version empty; fallback install will use latest compatible + } + + const packageSpec = esbuildVersion ? `${pkgName}@${esbuildVersion}` : pkgName + console.log("šŸ“¦ Step 0/3: Restoring esbuild platform binary...\n") + await run(npmCmd, ["install", packageSpec, "--no-save", "--ignore-scripts", "--fund=false", "--audit=false"], { + cwd: workspaceRoot, + env: { NODE_PATH: workspaceNodeModulesPath }, + }) +} + const platforms = { mac: { args: ["--mac", "--x64", "--arm64"], @@ -105,6 +145,8 @@ async function build(platform) { console.log(`\nšŸ”Ø Building for: ${config.description}\n`) try { + await ensureEsbuildPlatformBinary() + console.log("šŸ“¦ Step 1/3: Building CLI dependency...\n") await run(npmCmd, ["run", "build", "--workspace", "@neuralnomads/codenomad"], { cwd: workspaceRoot, diff --git a/packages/electron-app/scripts/prepare-resources.js b/packages/electron-app/scripts/prepare-resources.js index d44a4508..b2df71f9 100644 --- a/packages/electron-app/scripts/prepare-resources.js +++ b/packages/electron-app/scripts/prepare-resources.js @@ -16,6 +16,7 @@ const npmNodeExecPath = process.env.npm_node_execpath const serverSources = ["dist", "public", "node_modules", "package.json"] const serverDepsMarker = join(serverRoot, "node_modules", "fastify", "package.json") +const standaloneMarker = join(serverRoot, "dist", process.platform === "win32" ? "codenomad-server.exe" : "codenomad-server") function log(message) { console.log(`[prepare-resources] ${message}`) @@ -29,6 +30,34 @@ function ensureServerBuild() { } } +function ensureStandaloneServerBuild() { + log("building standalone server executable") + const result = spawnSync( + "npm", + ["run", "build:standalone", "--workspace", "@neuralnomads/codenomad"], + { + cwd: workspaceRoot, + stdio: "inherit", + env: { + ...process.env, + PATH: `${join(workspaceRoot, "node_modules", ".bin")}${path.delimiter}${process.env.PATH ?? ""}`, + }, + shell: process.platform === "win32", + }, + ) + + if (result.status !== 0) { + if (result.error) { + throw result.error + } + throw new Error(`standalone server build exited with code ${result.status ?? 1}`) + } + + if (!fs.existsSync(standaloneMarker)) { + throw new Error(`Standalone server executable missing after build: ${standaloneMarker}`) + } +} + function ensureServerDependencies() { if (fs.existsSync(serverDepsMarker)) { return @@ -65,6 +94,51 @@ function ensureServerDependencies() { } } +function ensureEsbuildPlatformBinary() { + const platformKey = `${process.platform}-${process.arch}` + const platformPackages = { + "linux-x64": "@esbuild/linux-x64", + "linux-arm64": "@esbuild/linux-arm64", + "darwin-arm64": "@esbuild/darwin-arm64", + "darwin-x64": "@esbuild/darwin-x64", + "win32-arm64": "@esbuild/win32-arm64", + "win32-x64": "@esbuild/win32-x64", + } + + const pkgName = platformPackages[platformKey] + if (!pkgName) { + return + } + + const platformPackagePath = join(workspaceRoot, "node_modules", ...pkgName.split("/")) + if (fs.existsSync(platformPackagePath)) { + return + } + + let esbuildVersion = "" + try { + esbuildVersion = JSON.parse(fs.readFileSync(join(workspaceRoot, "node_modules", "esbuild", "package.json"), "utf-8")).version ?? "" + } catch { + // leave version empty; fallback install will use latest compatible + } + + const packageSpec = esbuildVersion ? `${pkgName}@${esbuildVersion}` : pkgName + log("installing esbuild platform binary (optional dep workaround)") + + const result = spawnSync("npm", ["install", packageSpec, "--no-save", "--ignore-scripts", "--fund=false", "--audit=false"], { + cwd: workspaceRoot, + stdio: "inherit", + shell: process.platform === "win32", + }) + + if (result.status !== 0) { + if (result.error) { + throw result.error + } + throw new Error(`esbuild platform install exited with code ${result.status ?? 1}`) + } +} + function copyServerArtifacts() { fs.rmSync(serverDest, { recursive: true, force: true }) fs.mkdirSync(serverDest, { recursive: true }) @@ -121,7 +195,9 @@ function stripNodeModuleBins() { async function main() { ensureServerBuild() + ensureStandaloneServerBuild() ensureServerDependencies() + ensureEsbuildPlatformBinary() copyServerArtifacts() stripNodeModuleBins() } diff --git a/packages/opencode-config/package.json b/packages/opencode-config/package.json index 635f7716..a1c0f134 100644 --- a/packages/opencode-config/package.json +++ b/packages/opencode-config/package.json @@ -4,6 +4,6 @@ "private": true, "license": "MIT", "dependencies": { - "@opencode-ai/plugin": "1.3.7" + "@opencode-ai/plugin": "1.14.19" } -} \ No newline at end of file +} diff --git a/packages/server/package.json b/packages/server/package.json index dafda21e..ce667f0f 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -18,6 +18,7 @@ }, "scripts": { "build": "npm run build:ui && npm run prepare-ui && tsc -p tsconfig.json && node ./scripts/copy-auth-pages.mjs && npm run prepare-config", + "build:standalone": "node ./scripts/build-standalone.mjs", "build:ui": "npm run build --prefix ../ui", "prepare-ui": "node ./scripts/copy-ui-dist.mjs", "prepare-config": "node ./scripts/copy-opencode-config.mjs", @@ -25,16 +26,16 @@ "typecheck": "tsc --noEmit -p tsconfig.json" }, "dependencies": { - "@fastify/cors": "^8.5.0", - "@fastify/reply-from": "^9.8.0", - "@fastify/static": "^7.0.4", + "@fastify/cors": "^11.2.0", + "@fastify/reply-from": "^12.6.2", + "@fastify/static": "^9.1.1", "commander": "^12.1.0", - "fastify": "^4.28.1", + "fastify": "^5.8.5", "fuzzysort": "^2.0.4", "node-forge": "^1.3.3", "openai": "^6.27.0", "pino": "^9.4.0", - "undici": "^6.19.8", + "undici": "^8.1.0", "yaml": "^2.4.2", "yauzl": "^2.10.0", "zod": "^3.23.8" @@ -42,6 +43,7 @@ "devDependencies": { "@types/node-forge": "^1.3.14", "@types/yauzl": "^2.10.0", + "bun": "^1.3.13", "cross-env": "^7.0.3", "ts-node": "^10.9.2", "tsx": "^4.20.6", diff --git a/packages/server/scripts/build-standalone.mjs b/packages/server/scripts/build-standalone.mjs new file mode 100644 index 00000000..3802636f --- /dev/null +++ b/packages/server/scripts/build-standalone.mjs @@ -0,0 +1,99 @@ +#!/usr/bin/env node +import fs from "fs" +import path from "path" +import { spawnSync } from "child_process" +import { fileURLToPath } from "url" + +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) +const cliRoot = path.resolve(__dirname, "..") +const distDir = path.join(cliRoot, "dist") +const publicDir = path.join(cliRoot, "public") +const authPagesSourceDir = path.join(distDir, "server", "routes", "auth-pages") +const authPagesTargetDir = path.join(distDir, "auth-pages") +const explicitTarget = process.env.CODENOMAD_STANDALONE_TARGET?.trim() +const outputName = (explicitTarget?.includes("windows") || process.platform === "win32") ? "codenomad-server.exe" : "codenomad-server" +const outputPath = path.join(distDir, outputName) +const packageJsonPath = path.join(cliRoot, "package.json") + +function resolveBunCommand() { + const executableName = process.platform === "win32" ? "bun.exe" : "bun" + const localBinName = process.platform === "win32" ? "bun.cmd" : "bun" + const candidates = [ + path.join(cliRoot, "node_modules", ".bin", localBinName), + path.join(cliRoot, "..", "..", "node_modules", ".bin", localBinName), + path.join(cliRoot, "node_modules", "bun", "bin", executableName), + path.join(cliRoot, "..", "..", "node_modules", "bun", "bin", executableName), + ] + + for (const candidate of candidates) { + if (fs.existsSync(candidate)) { + return candidate + } + } + + return "bun" +} + +function fail(message) { + console.error(`[build-standalone] ${message}`) + process.exit(1) +} + +function ensureArtifacts() { + const requiredPaths = [distDir, publicDir, authPagesSourceDir, packageJsonPath] + const missing = requiredPaths.filter((filePath) => !fs.existsSync(filePath)) + if (missing.length > 0) { + fail(`Missing required build artifacts: ${missing.join(", ")}. Run npm run build first.`) + } + + const bunResult = spawnSync(resolveBunCommand(), ["-v"], { cwd: cliRoot, encoding: "utf-8", shell: process.platform === "win32" }) + if (bunResult.status !== 0) { + fail("Bun is required to build the standalone server executable. Install dependencies so the local Bun binary is available.") + } +} + +function syncStandaloneAuthPages() { + fs.rmSync(authPagesTargetDir, { recursive: true, force: true }) + fs.mkdirSync(path.dirname(authPagesTargetDir), { recursive: true }) + fs.cpSync(authPagesSourceDir, authPagesTargetDir, { recursive: true }) +} + +function buildStandaloneExecutable() { + fs.rmSync(outputPath, { force: true }) + const bunCommand = resolveBunCommand() + + const args = ["build", "--compile"] + if (explicitTarget) { + args.push(`--target=${explicitTarget}`) + } + args.push(path.join(cliRoot, "src", "index.ts"), "--outfile", outputPath) + + const result = spawnSync(bunCommand, args, { + cwd: cliRoot, + stdio: "inherit", + shell: process.platform === "win32", + }) + + if (result.status !== 0) { + if (result.error) { + throw result.error + } + throw new Error(`bun build --compile exited with code ${result.status ?? 1}`) + } +} + +function main() { + ensureArtifacts() + syncStandaloneAuthPages() + + buildStandaloneExecutable() + console.log(`[build-standalone] built ${outputPath}`) +} + +try { + main() +} catch (error) { + console.error("[build-standalone] failed:", error) + process.exit(1) +} diff --git a/packages/server/scripts/copy-opencode-config.mjs b/packages/server/scripts/copy-opencode-config.mjs index 5e714395..48049d4b 100644 --- a/packages/server/scripts/copy-opencode-config.mjs +++ b/packages/server/scripts/copy-opencode-config.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node import { spawnSync } from "child_process" -import { cpSync, existsSync, mkdirSync, rmSync } from "fs" +import { cpSync, existsSync, mkdirSync, readdirSync, rmSync } from "fs" import path from "path" import { fileURLToPath } from "url" @@ -14,6 +14,67 @@ const selfLinkDir = path.resolve(nodeModulesDir, "@codenomad", "opencode-config" const npmExecPath = process.env.npm_execpath const npmNodeExecPath = process.env.npm_node_execpath +function stripNodeModuleBins(rootDir) { + const root = path.join(rootDir, "node_modules") + if (!existsSync(root)) { + return 0 + } + + const stack = [root] + let removed = 0 + + while (stack.length > 0) { + const current = stack.pop() + if (!current) break + + let entries + try { + entries = readdirSync(current, { withFileTypes: true }) + } catch { + continue + } + + for (const entry of entries) { + const full = path.join(current, entry.name) + if (entry.name === ".bin") { + rmSync(full, { recursive: true, force: true }) + removed += 1 + continue + } + + if (entry.isDirectory()) { + stack.push(full) + } + } + } + + return removed +} + +function stripOptionalNativeAddons(rootDir) { + const nodeModulesRoot = path.join(rootDir, "node_modules") + if (!existsSync(nodeModulesRoot)) { + return 0 + } + + const removablePaths = [ + path.join(nodeModulesRoot, "@msgpackr-extract"), + path.join(nodeModulesRoot, "msgpackr-extract"), + ] + + let removed = 0 + for (const targetPath of removablePaths) { + if (!existsSync(targetPath)) { + continue + } + + rmSync(targetPath, { recursive: true, force: true }) + removed += 1 + } + + return removed +} + if (!existsSync(sourceDir)) { console.error(`[copy-opencode-config] Missing source directory at ${sourceDir}`) process.exit(1) @@ -58,4 +119,14 @@ rmSync(targetDir, { recursive: true, force: true }) mkdirSync(path.dirname(targetDir), { recursive: true }) cpSync(sourceDir, targetDir, { recursive: true }) +const removedBins = stripNodeModuleBins(targetDir) +if (removedBins > 0) { + console.log(`[copy-opencode-config] Removed ${removedBins} node_modules/.bin directories`) +} + +const removedNativeAddons = stripOptionalNativeAddons(targetDir) +if (removedNativeAddons > 0) { + console.log(`[copy-opencode-config] Removed ${removedNativeAddons} optional native addon package paths`) +} + console.log(`[copy-opencode-config] Copied ${sourceDir} -> ${targetDir}`) diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index c021d220..f8418c5c 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -29,13 +29,14 @@ import { SideCarManager } from "./sidecars/manager" import { ClientConnectionManager } from "./clients/connection-manager" import { PluginChannelManager } from "./plugins/channel" import { VoiceModeManager } from "./plugins/voice-mode" +import { readServerPackageVersion, resolveServerPublicDir } from "./runtime-paths" const require = createRequire(import.meta.url) -const packageJson = require("../package.json") as { version: string } +const packageJson = { version: readServerPackageVersion(import.meta.url) } const __filename = fileURLToPath(import.meta.url) const __dirname = path.dirname(__filename) -const DEFAULT_UI_STATIC_DIR = path.resolve(__dirname, "../public") +const DEFAULT_UI_STATIC_DIR = resolveServerPublicDir(import.meta.url) interface CliOptions { host: string diff --git a/packages/server/src/opencode-config.ts b/packages/server/src/opencode-config.ts index f61cb9ca..4495b6e9 100644 --- a/packages/server/src/opencode-config.ts +++ b/packages/server/src/opencode-config.ts @@ -1,22 +1,11 @@ import { existsSync } from "fs" -import path from "path" -import { fileURLToPath } from "url" import { createLogger } from "./logger" +import { resolveOpencodeTemplateDir } from "./runtime-paths" const log = createLogger({ component: "opencode-config" }) -const __filename = fileURLToPath(import.meta.url) -const __dirname = path.dirname(__filename) -const devTemplateDir = path.resolve(__dirname, "../../opencode-config") -const resourcesPath = (process as NodeJS.Process & { resourcesPath?: string }).resourcesPath -const prodTemplateDirs = [ - resourcesPath ? path.resolve(resourcesPath, "opencode-config") : undefined, - path.resolve(__dirname, "opencode-config"), -].filter((dir): dir is string => Boolean(dir)) +const templateDir = resolveOpencodeTemplateDir(import.meta.url) -const isDevBuild = Boolean(process.env.CODENOMAD_DEV ?? process.env.CLI_UI_DEV_SERVER) || existsSync(devTemplateDir) -const templateDir = isDevBuild - ? devTemplateDir - : prodTemplateDirs.find((dir) => existsSync(dir)) ?? prodTemplateDirs[0] +const isDevBuild = Boolean(process.env.CODENOMAD_DEV ?? process.env.CLI_UI_DEV_SERVER) export function getOpencodeConfigDir(): string { if (!existsSync(templateDir)) { diff --git a/packages/server/src/runtime-paths.ts b/packages/server/src/runtime-paths.ts new file mode 100644 index 00000000..afae95d1 --- /dev/null +++ b/packages/server/src/runtime-paths.ts @@ -0,0 +1,79 @@ +import fs from "fs" +import path from "path" +import { fileURLToPath } from "url" + +function safeModuleDir(importMetaUrl: string): string | null { + try { + return path.dirname(fileURLToPath(importMetaUrl)) + } catch { + return null + } +} + +function firstExistingPath(candidates: Array, predicate: (value: string) => boolean): string | null { + for (const candidate of candidates) { + if (!candidate) continue + if (predicate(candidate)) { + return candidate + } + } + return null +} + +export function getPackagedDistDir(): string { + return path.dirname(process.execPath) +} + +export function resolveServerPackageRoot(importMetaUrl: string): string { + const moduleDir = safeModuleDir(importMetaUrl) + const configuredRoot = process.env.CODENOMAD_SERVER_ROOT?.trim() + const candidates = [ + configuredRoot ? path.resolve(configuredRoot) : null, + moduleDir ? path.resolve(moduleDir, "..") : null, + path.resolve(getPackagedDistDir(), ".."), + ] + + return ( + firstExistingPath(candidates, (value) => fs.existsSync(path.join(value, "package.json"))) ?? + candidates.find((value): value is string => Boolean(value)) ?? + process.cwd() + ) +} + +export function resolveServerPublicDir(importMetaUrl: string): string { + const moduleDir = safeModuleDir(importMetaUrl) + const candidates = [moduleDir ? path.resolve(moduleDir, "../public") : null, path.join(resolveServerPackageRoot(importMetaUrl), "public")] + + return firstExistingPath(candidates, (value) => fs.existsSync(value)) ?? candidates[candidates.length - 1]! +} + +export function resolveAuthTemplatePath(importMetaUrl: string, fileName: string): string { + const moduleDir = safeModuleDir(importMetaUrl) + const distDir = getPackagedDistDir() + const candidates = [ + moduleDir ? path.join(moduleDir, "auth-pages", fileName) : null, + path.join(distDir, "auth-pages", fileName), + path.join(distDir, "server", "routes", "auth-pages", fileName), + ] + + return firstExistingPath(candidates, (value) => fs.existsSync(value)) ?? candidates[0]! +} + +export function resolveOpencodeTemplateDir(importMetaUrl: string): string { + const moduleDir = safeModuleDir(importMetaUrl) + const resourcesPath = (process as NodeJS.Process & { resourcesPath?: string }).resourcesPath + const candidates = [ + moduleDir ? path.resolve(moduleDir, "../../opencode-config") : null, + resourcesPath ? path.resolve(resourcesPath, "opencode-config") : null, + moduleDir ? path.resolve(moduleDir, "opencode-config") : null, + path.join(getPackagedDistDir(), "opencode-config"), + ] + + return firstExistingPath(candidates, (value) => fs.existsSync(value)) ?? candidates[candidates.length - 1]! +} + +export function readServerPackageVersion(importMetaUrl: string): string { + const packageJsonPath = path.join(resolveServerPackageRoot(importMetaUrl), "package.json") + const parsed = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8")) as { version?: unknown } + return typeof parsed.version === "string" && parsed.version.trim().length > 0 ? parsed.version : "0.0.0" +} diff --git a/packages/server/src/server/http-server.ts b/packages/server/src/server/http-server.ts index cf7dae36..f7ef029b 100644 --- a/packages/server/src/server/http-server.ts +++ b/packages/server/src/server/http-server.ts @@ -5,6 +5,8 @@ import replyFrom from "@fastify/reply-from" import fs from "fs" import { connect as connectTcp, type Socket } from "net" import path from "path" +import { Readable } from "stream" +import { pipeline } from "stream/promises" import { connect as connectTls, type TLSSocket } from "tls" import { fetch } from "undici" import type { Logger } from "../logger" @@ -626,57 +628,57 @@ async function proxyWorkspaceRequest(args: { logger.trace({ workspaceId, targetUrl, body: request.body }, "Instance proxy payload") } - return reply.from(targetUrl, { - rewriteRequestHeaders: (_originalRequest, headers) => { - if (instanceAuthHeader) { - headers.authorization = instanceAuthHeader - } + const headers = buildWorkspaceInstanceProxyHeaders(request.headers, instanceAuthHeader, directory) - // OpenCode expects the *full* path; we send it via header to avoid query tampering. - const isNonASCII = /[^\x00-\x7F]/.test(directory) - const encodedDirectory = isNonASCII ? encodeURIComponent(directory) : directory + if (logger.isLevelEnabled("trace")) { + logger.trace( + { + workspaceId, + method: request.method, + targetUrl, + worktreeSlug, + directory, + contentType: request.headers["content-type"], + body: bodyToJson(request.body), + headers: redactProxyHeadersForLogs(headers), + }, + "Proxy -> OpenCode request", + ) + } - // Overwrite any client-provided value (case-insensitive headers are normalized by Node). - ;(headers as Record)["x-opencode-directory"] = encodedDirectory + const init: any = { + method: request.method, + headers, + redirect: "manual", + } - if (logger.isLevelEnabled("trace")) { - const outgoing: Record = {} - for (const [key, value] of Object.entries(headers as Record)) { - outgoing[key] = value - } + if (request.method !== "GET" && request.method !== "HEAD") { + const body = toProxyRequestBody(request.body) + if (body !== undefined) { + init.body = body + init.duplex = "half" + } + } - // Redact sensitive headers. - for (const key of Object.keys(outgoing)) { - const lower = key.toLowerCase() - if (lower === "authorization" || lower === "cookie" || lower === "set-cookie") { - outgoing[key] = "" - } - } + try { + const response = await fetch(targetUrl, init) + reply.code(response.status) + applyInstanceProxyResponseHeaders(reply, response) - logger.trace( - { - workspaceId, - method: request.method, - targetUrl, - worktreeSlug, - directory, - contentType: request.headers["content-type"], - body: bodyToJson(request.body), - headers: outgoing, - }, - "Proxy -> OpenCode request", - ) - } + if (!response.body || request.method === "HEAD") { + reply.send() + return + } - return headers - }, - onError: (proxyReply, { error }) => { - logger.error({ err: error, workspaceId, targetUrl }, "Failed to proxy workspace request") - if (!proxyReply.sent) { - proxyReply.code(502).send({ error: "Workspace instance proxy failed" }) - } - }, - }) + reply.hijack() + reply.raw.writeHead(reply.statusCode, toOutgoingHeaders(reply.getHeaders())) + await pipeline(Readable.fromWeb(response.body as any), reply.raw) + } catch (error) { + logger.error({ err: error, workspaceId, targetUrl }, "Failed to proxy workspace request") + if (!reply.sent) { + reply.code(502).send({ error: "Workspace instance proxy failed" }) + } + } } function extractOpencodeDirectoryOverride(pathSuffix: string | undefined): { @@ -867,12 +869,90 @@ function isApiRequest(rawUrl: string | null | undefined) { function buildProxyHeaders(headers: FastifyRequest["headers"]): Record { const result: Record = {} for (const [key, value] of Object.entries(headers ?? {})) { - if (!value || key.toLowerCase() === "host") continue + const lower = key.toLowerCase() + if (!value || lower === "host" || isHopByHopHeader(lower)) continue result[key] = Array.isArray(value) ? value.join(",") : value } return result } +function toProxyRequestBody(body: unknown): any { + if (body == null) { + return undefined + } + if (typeof (body as { pipe?: unknown }).pipe === "function") { + return body + } + if (typeof (body as { [Symbol.asyncIterator]?: unknown })[Symbol.asyncIterator] === "function") { + return body + } + if (Buffer.isBuffer(body) || typeof body === "string" || body instanceof Uint8Array) { + return body + } + return JSON.stringify(body) +} + +function buildWorkspaceInstanceProxyHeaders( + headers: FastifyRequest["headers"], + instanceAuthHeader: string | undefined, + directory: string, +): Record { + const next = buildProxyHeaders(headers) + if (instanceAuthHeader) { + next.authorization = instanceAuthHeader + } + + const isNonASCII = /[^\x00-\x7F]/.test(directory) + next["x-opencode-directory"] = isNonASCII ? encodeURIComponent(directory) : directory + return next +} + +function redactProxyHeadersForLogs(headers: Record): Record { + const outgoing = { ...headers } + for (const key of Object.keys(outgoing)) { + const lower = key.toLowerCase() + if (lower === "authorization" || lower === "cookie" || lower === "set-cookie") { + outgoing[key] = "" + } + } + return outgoing +} + +function applyInstanceProxyResponseHeaders(reply: FastifyReply, response: any) { + response.headers.forEach((value: string, key: string) => { + const lower = key.toLowerCase() + if (isHopByHopHeader(lower) || lower === "content-length" || lower === "content-encoding") { + return + } + + reply.header(key, value) + }) +} + +function toOutgoingHeaders(headers: ReturnType): Record { + const next: Record = {} + for (const [key, value] of Object.entries(headers)) { + if (value === undefined) { + continue + } + next[key] = Array.isArray(value) ? value.map(String) : String(value) + } + return next +} + +function isHopByHopHeader(name: string): boolean { + return new Set([ + "connection", + "keep-alive", + "proxy-authenticate", + "proxy-authorization", + "te", + "trailer", + "transfer-encoding", + "upgrade", + ]).has(name) +} + async function proxySideCarRequest(args: { request: FastifyRequest reply: FastifyReply diff --git a/packages/server/src/server/routes/auth.ts b/packages/server/src/server/routes/auth.ts index 6bb7d3d3..0e954589 100644 --- a/packages/server/src/server/routes/auth.ts +++ b/packages/server/src/server/routes/auth.ts @@ -3,6 +3,7 @@ import fs from "fs" import { z } from "zod" import type { AuthManager } from "../../auth/manager" import { isLoopbackAddress } from "../../auth/http-auth" +import { resolveAuthTemplatePath } from "../../runtime-paths" interface RouteDeps { authManager: AuthManager @@ -21,21 +22,21 @@ const PasswordSchema = z.object({ password: z.string().min(8), }) -const LOGIN_TEMPLATE_URL = new URL("./auth-pages/login.html", import.meta.url) -const TOKEN_TEMPLATE_URL = new URL("./auth-pages/token.html", import.meta.url) +const LOGIN_TEMPLATE_PATH = resolveAuthTemplatePath(import.meta.url, "login.html") +const TOKEN_TEMPLATE_PATH = resolveAuthTemplatePath(import.meta.url, "token.html") let cachedLoginTemplate: string | null = null let cachedTokenTemplate: string | null = null -function readTemplate(url: URL, cache: string | null): string { +function readTemplate(filePath: string, cache: string | null): string { if (cache) return cache - const content = fs.readFileSync(url, "utf-8") + const content = fs.readFileSync(filePath, "utf-8") return content } function getLoginHtml(defaultUsername: string): string { if (!cachedLoginTemplate) { - cachedLoginTemplate = readTemplate(LOGIN_TEMPLATE_URL, null) + cachedLoginTemplate = readTemplate(LOGIN_TEMPLATE_PATH, null) } const escapedUsername = escapeHtml(defaultUsername) @@ -44,7 +45,7 @@ function getLoginHtml(defaultUsername: string): string { function getTokenHtml(): string { if (!cachedTokenTemplate) { - cachedTokenTemplate = readTemplate(TOKEN_TEMPLATE_URL, null) + cachedTokenTemplate = readTemplate(TOKEN_TEMPLATE_PATH, null) } return cachedTokenTemplate diff --git a/packages/server/src/workspaces/manager.ts b/packages/server/src/workspaces/manager.ts index dc939758..56ebef17 100644 --- a/packages/server/src/workspaces/manager.ts +++ b/packages/server/src/workspaces/manager.ts @@ -21,6 +21,70 @@ import { const STARTUP_STABILITY_DELAY_MS = 1500 +function defaultShellPath(): string { + const configured = process.env.SHELL?.trim() + if (configured) { + return configured + } + + return process.platform === "darwin" ? "/bin/zsh" : "/bin/bash" +} + +function shellEscape(input: string): string { + if (!input) return "''" + return `'${input.replace(/'/g, `'\\''`)}'` +} + +function wrapCommandForShell(command: string, shellPath: string): string { + const shellName = path.basename(shellPath).toLowerCase() + + if (shellName.includes("bash")) { + return `if [ -f ~/.bashrc ]; then source ~/.bashrc >/dev/null 2>&1; fi; ${command}` + } + + if (shellName.includes("zsh")) { + return `if [ -f ~/.zshrc ]; then source ~/.zshrc >/dev/null 2>&1; fi; ${command}` + } + + return command +} + +function buildShellArgs(shellPath: string, command: string): string[] { + const shellName = path.basename(shellPath).toLowerCase() + if (shellName.includes("zsh")) { + return ["-l", "-i", "-c", command] + } + return ["-l", "-c", command] +} + +function resolveBinaryPathFromUserShell(identifier: string): string | null { + if (process.platform === "win32") { + return null + } + + const shellPath = defaultShellPath() + const lookupCommand = wrapCommandForShell(`command -v ${shellEscape(identifier)}`, shellPath) + const result = spawnSync(shellPath, buildShellArgs(shellPath, lookupCommand), { + encoding: "utf8", + env: { + ...process.env, + npm_config_prefix: undefined, + NPM_CONFIG_PREFIX: undefined, + }, + }) + + if (result.status !== 0) { + return null + } + + const resolved = String(result.stdout ?? "") + .split(/\r?\n/) + .map((line) => line.trim()) + .find((line) => line.length > 0) + + return resolved ?? null +} + interface WorkspaceManagerOptions { rootDir: string settings: SettingsService @@ -266,6 +330,12 @@ export class WorkspaceManager { this.options.logger.warn({ identifier, err: error }, "Failed to resolve binary path from system PATH") } + const shellResolved = resolveBinaryPathFromUserShell(identifier) + if (shellResolved) { + this.options.logger.debug({ identifier, resolved: shellResolved }, "Resolved binary path from user shell") + return shellResolved + } + return identifier } diff --git a/packages/tauri-app/package.json b/packages/tauri-app/package.json index c09a70ac..6f627aef 100644 --- a/packages/tauri-app/package.json +++ b/packages/tauri-app/package.json @@ -14,6 +14,6 @@ "build": "tauri build" }, "devDependencies": { - "@tauri-apps/cli": "^2.9.4" + "@tauri-apps/cli": "^2.10.1" } } diff --git a/packages/tauri-app/scripts/prebuild.js b/packages/tauri-app/scripts/prebuild.js index a234af46..879de496 100644 --- a/packages/tauri-app/scripts/prebuild.js +++ b/packages/tauri-app/scripts/prebuild.js @@ -21,6 +21,7 @@ const serverDevInstallCommand = const uiDevInstallCommand = "npm install --workspace @codenomad/ui --include-workspace-root=false --install-strategy=nested --fund=false --audit=false" const serverPrepareUiCommand = "npm run prepare-ui --workspace @neuralnomads/codenomad" +const serverStandaloneBuildCommand = "npm run build:standalone --workspace @neuralnomads/codenomad" const envWithRootBin = { ...process.env, @@ -77,6 +78,15 @@ function ensureServerBuild() { } } +function ensureStandaloneServerBuild() { + console.log("[prebuild] building standalone server executable...") + execSync(serverStandaloneBuildCommand, { + cwd: workspaceRoot, + stdio: "inherit", + env: envWithRootBin, + }) +} + function ensureUiBuild() { const loadingHtml = path.join(uiDist, "loading.html") if (fs.existsSync(loadingHtml)) { @@ -117,15 +127,19 @@ function ensureServerDevDependencies() { } function ensureServerDependencies() { - if (fs.existsSync(braceExpansionPath)) { - return - } - - console.log("[prebuild] ensuring server production dependencies...") - execSync(serverInstallCommand, { + console.log("[prebuild] pruning server to production dependencies...") + execSync("npm prune --omit=dev --ignore-scripts --workspaces=false --fund=false --audit=false", { cwd: serverRoot, stdio: "inherit", }) + + if (!fs.existsSync(braceExpansionPath)) { + console.log("[prebuild] restoring missing server production dependencies...") + execSync(serverInstallCommand, { + cwd: serverRoot, + stdio: "inherit", + }) + } } function ensureUiDevDependencies() { @@ -178,6 +192,47 @@ function ensureRollupPlatformBinary() { }) } +function ensureEsbuildPlatformBinary() { + const platformKey = `${process.platform}-${process.arch}` + const platformPackages = { + "linux-x64": "@esbuild/linux-x64", + "linux-arm64": "@esbuild/linux-arm64", + "darwin-arm64": "@esbuild/darwin-arm64", + "darwin-x64": "@esbuild/darwin-x64", + "win32-arm64": "@esbuild/win32-arm64", + "win32-x64": "@esbuild/win32-x64", + } + + const pkgName = platformPackages[platformKey] + if (!pkgName) { + return + } + + const platformPackagePath = path.join(workspaceRoot, "node_modules", ...pkgName.split("/")) + if (fs.existsSync(platformPackagePath)) { + return + } + + let esbuildVersion = "" + try { + esbuildVersion = require(path.join(workspaceRoot, "node_modules", "esbuild", "package.json")).version + } catch { + try { + esbuildVersion = require(path.join(workspaceRoot, "node_modules", "vite", "node_modules", "esbuild", "package.json")).version + } catch { + // leave version empty; fallback install will use latest compatible + } + } + + const packageSpec = esbuildVersion ? `${pkgName}@${esbuildVersion}` : pkgName + + console.log("[prebuild] installing esbuild platform binary (optional dep workaround)...") + execSync(`npm install ${packageSpec} --no-save --ignore-scripts --fund=false --audit=false`, { + cwd: workspaceRoot, + stdio: "inherit", + }) +} + function copyServerArtifacts() { fs.rmSync(serverDest, { recursive: true, force: true }) fs.mkdirSync(serverDest, { recursive: true }) @@ -256,8 +311,10 @@ function copyUiLoadingAssets() { ensureUiDevDependencies() await ensureMonacoAssets() ensureRollupPlatformBinary() - ensureServerDependencies() + ensureEsbuildPlatformBinary() ensureServerBuild() + ensureStandaloneServerBuild() + ensureServerDependencies() ensureUiBuild() syncServerUiBundle() copyServerArtifacts() diff --git a/packages/tauri-app/src-tauri/Cargo.toml b/packages/tauri-app/src-tauri/Cargo.toml index 940e9fbf..a17d771b 100644 --- a/packages/tauri-app/src-tauri/Cargo.toml +++ b/packages/tauri-app/src-tauri/Cargo.toml @@ -5,10 +5,10 @@ edition = "2021" license = "MIT" [build-dependencies] -tauri-build = { version = "2.5.2", features = [] } +tauri-build = { version = "2.5.6", features = [] } [dependencies] -tauri = { version = "2.5.2", features = [ "devtools"] } +tauri = { version = "2.10.1", features = [ "devtools"] } serde = { version = "1", features = ["derive"] } serde_json = "1" serde_yaml = "0.9" diff --git a/packages/tauri-app/src-tauri/src/cli_manager.rs b/packages/tauri-app/src-tauri/src/cli_manager.rs index a0efd38a..1f11a8b7 100644 --- a/packages/tauri-app/src-tauri/src/cli_manager.rs +++ b/packages/tauri-app/src-tauri/src/cli_manager.rs @@ -136,6 +136,10 @@ fn workspace_root() -> Option { }) } +fn launch_cwd() -> Option { + std::env::current_dir().ok() +} + const SESSION_COOKIE_NAME_PREFIX: &str = "codenomad_session"; const CLI_STOP_GRACE_SECS: u64 = 30; @@ -624,16 +628,19 @@ impl CliProcessManager { log_line("development mode: will prefer tsx + source if present"); } - let cwd = workspace_root(); + let cwd = launch_cwd(); if let Some(ref c) = cwd { log_line(&format!("using cwd={}", c.display())); } let use_user_shell = supports_user_shell(); - if !use_user_shell && which::which(&resolution.node_binary).is_err() { + if resolution.runner == Runner::Tsx + && !use_user_shell + && which::which(&resolution.node_binary).is_err() + { return Err(anyhow::anyhow!( - "Node binary '{}' not found. CodeNomad desktop currently requires Node.js installed on the system, or set NODE_BINARY to a valid runtime path.", + "Node binary '{}' not found. CodeNomad development mode requires Node.js installed on the system, or set NODE_BINARY to a valid runtime path.", resolution.node_binary )); } @@ -642,9 +649,17 @@ impl CliProcessManager { log_line("spawning via user shell"); ShellCommandType::UserShell(build_shell_command_string(&resolution, &args)?) } else { - log_line("spawning directly with node"); + log_line(if resolution.runner == Runner::Standalone { + "spawning directly with standalone executable" + } else { + "spawning directly with node" + }); ShellCommandType::Direct(DirectCommand { - program: resolution.node_binary.clone(), + program: if resolution.runner == Runner::Standalone { + resolution.entry.clone() + } else { + resolution.node_binary.clone() + }, args: resolution.runner_args(&args), }) }; @@ -654,11 +669,13 @@ impl CliProcessManager { log_line(&format!("spawn command: {} {:?}", cmd.shell, cmd.args)); let mut c = Command::new(&cmd.shell); c.args(&cmd.args) - .env("ELECTRON_RUN_AS_NODE", "1") .env_remove("npm_config_prefix") .env_remove("NPM_CONFIG_PREFIX") .stdout(Stdio::piped()) .stderr(Stdio::piped()); + if resolution.runner != Runner::Standalone { + c.env("ELECTRON_RUN_AS_NODE", "1"); + } configure_spawn(&mut c); if let Some(ref cwd) = cwd { c.current_dir(cwd); @@ -671,9 +688,11 @@ impl CliProcessManager { log_line(&format!("spawn command: {} {:?}", cmd.program, cmd.args)); let mut c = Command::new(&cmd.program); c.args(&cmd.args) - .env("ELECTRON_RUN_AS_NODE", "1") .stdout(Stdio::piped()) .stderr(Stdio::piped()); + if resolution.runner != Runner::Standalone { + c.env("ELECTRON_RUN_AS_NODE", "1"); + } configure_spawn(&mut c); if let Some(ref cwd) = cwd { c.current_dir(cwd); @@ -924,7 +943,7 @@ impl CliProcessManager { let mut locked = status.lock(); if locked.error.is_none() { locked.error = Some(format!( - "Node binary '{}' not found in the desktop shell environment. CodeNomad desktop currently requires Node.js installed on the system, or set NODE_BINARY to a valid runtime path.", + "Node binary '{}' not found in the desktop shell environment. CodeNomad development mode requires Node.js installed on the system, or set NODE_BINARY to a valid runtime path.", node_binary.trim() )); } @@ -1047,7 +1066,7 @@ struct CliEntry { #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum Runner { - Node, + Standalone, Tsx, } @@ -1068,17 +1087,17 @@ impl CliEntry { } } - if let Some(entry) = resolve_dist_entry(app) { + if let Some(entry) = resolve_standalone_entry(app) { return Ok(Self { entry, - runner: Runner::Node, + runner: Runner::Standalone, runner_path: None, - node_binary, + node_binary: String::new(), }); } Err(anyhow::anyhow!( - "Unable to locate CodeNomad CLI build (dist/bin.js). Please build @neuralnomads/codenomad." + "Unable to locate the packaged CodeNomad standalone server. Please rebuild the desktop bundle." )) } @@ -1132,6 +1151,10 @@ impl CliEntry { } fn runner_args(&self, cli_args: &[String]) -> Vec { + if self.runner == Runner::Standalone { + return cli_args.to_vec(); + } + let mut args = VecDeque::new(); if self.runner == Runner::Tsx { if let Some(path) = &self.runner_path { @@ -1204,45 +1227,37 @@ fn resolve_dev_entry(_app: &AppHandle) -> Option { first_existing(candidates) } -fn resolve_dist_entry(_app: &AppHandle) -> Option { +fn resolve_standalone_entry(_app: &AppHandle) -> Option { + let executable_name = if cfg!(windows) { + "codenomad-server.exe" + } else { + "codenomad-server" + }; let base = workspace_root(); - let mut candidates: Vec> = vec![ - base.as_ref().map(|p| p.join("packages/server/dist/bin.js")), - base.as_ref() - .map(|p| p.join("packages/server/dist/index.js")), - base.as_ref().map(|p| p.join("server/dist/bin.js")), - base.as_ref().map(|p| p.join("server/dist/index.js")), - ]; + let mut candidates = vec![base + .as_ref() + .map(|p| p.join("packages/server/dist").join(executable_name))]; if let Ok(exe) = std::env::current_exe() { if let Some(dir) = exe.parent() { - candidates.push(Some(dir.join("resources/server/dist/bin.js"))); - candidates.push(Some(dir.join("resources/server/dist/index.js"))); - candidates.push(Some(dir.join("resources/server/dist/server/bin.js"))); - candidates.push(Some(dir.join("resources/server/dist/server/index.js"))); + candidates.push(Some( + dir.join("resources/server/dist").join(executable_name), + )); let resources = dir.join("../Resources"); - candidates.push(Some(resources.join("server/dist/bin.js"))); - candidates.push(Some(resources.join("server/dist/index.js"))); - candidates.push(Some(resources.join("server/dist/server/bin.js"))); - candidates.push(Some(resources.join("server/dist/server/index.js"))); - candidates.push(Some(resources.join("resources/server/dist/bin.js"))); - candidates.push(Some(resources.join("resources/server/dist/index.js"))); - candidates.push(Some(resources.join("resources/server/dist/server/bin.js"))); + candidates.push(Some(resources.join("server/dist").join(executable_name))); candidates.push(Some( - resources.join("resources/server/dist/server/index.js"), + resources + .join("resources/server/dist") + .join(executable_name), )); let linux_resource_roots = [dir.join("../lib/CodeNomad"), dir.join("../lib/codenomad")]; for root in linux_resource_roots { - candidates.push(Some(root.join("server/dist/bin.js"))); - candidates.push(Some(root.join("server/dist/index.js"))); - candidates.push(Some(root.join("server/dist/server/bin.js"))); - candidates.push(Some(root.join("server/dist/server/index.js"))); - candidates.push(Some(root.join("resources/server/dist/bin.js"))); - candidates.push(Some(root.join("resources/server/dist/index.js"))); - candidates.push(Some(root.join("resources/server/dist/server/bin.js"))); - candidates.push(Some(root.join("resources/server/dist/server/index.js"))); + candidates.push(Some(root.join("server/dist").join(executable_name))); + candidates.push(Some( + root.join("resources/server/dist").join(executable_name), + )); } } } @@ -1256,22 +1271,55 @@ fn build_shell_command_string( ) -> anyhow::Result { let shell = default_shell(); let mut quoted: Vec = Vec::new(); - quoted.push(shell_escape(&entry.node_binary)); - for arg in entry.runner_args(cli_args) { - quoted.push(shell_escape(&arg)); - } - let command = format!( - "if command -v {} >/dev/null 2>&1; then ELECTRON_RUN_AS_NODE=1 exec {}; else printf '%s%s\\n' '{}' {} >&2; exit 127; fi", - shell_escape(&entry.node_binary), - quoted.join(" "), - MISSING_NODE_PREFIX, - shell_escape(&entry.node_binary), - ); - let args = build_shell_args(&shell, &command); + let command = if entry.runner == Runner::Standalone { + quoted.push(shell_escape(&entry.entry)); + for arg in cli_args { + quoted.push(shell_escape(arg)); + } + format!("exec {}", quoted.join(" ")) + } else { + quoted.push(shell_escape(&entry.node_binary)); + for arg in entry.runner_args(cli_args) { + quoted.push(shell_escape(&arg)); + } + format!( + "if command -v {} >/dev/null 2>&1; then ELECTRON_RUN_AS_NODE=1 exec {}; else printf '%s%s\\n' '{}' {} >&2; exit 127; fi", + shell_escape(&entry.node_binary), + quoted.join(" "), + MISSING_NODE_PREFIX, + shell_escape(&entry.node_binary), + ) + }; + let wrapped_command = wrap_command_for_shell(&command, &shell); + let args = build_shell_args(&shell, &wrapped_command); log_line(&format!("user shell command: {} {:?}", shell, args)); Ok(ShellCommand { shell, args }) } +fn wrap_command_for_shell(command: &str, shell: &str) -> String { + let shell_name = std::path::Path::new(shell) + .file_name() + .and_then(OsStr::to_str) + .unwrap_or("") + .to_lowercase(); + + if shell_name.contains("bash") { + return format!( + "if [ -f ~/.bashrc ]; then source ~/.bashrc >/dev/null 2>&1; fi; {}", + command + ); + } + + if shell_name.contains("zsh") { + return format!( + "if [ -f ~/.zshrc ]; then source ~/.zshrc >/dev/null 2>&1; fi; {}", + command + ); + } + + command.to_string() +} + fn default_shell() -> String { if let Ok(shell) = std::env::var("SHELL") { if !shell.trim().is_empty() { @@ -1306,8 +1354,8 @@ fn build_shell_args(shell: &str, command: &str) -> Vec { .unwrap_or("") .to_lowercase(); - if shell_name.contains("zsh") || shell_name.contains("bash") { - vec!["-i".into(), "-l".into(), "-c".into(), command.into()] + if shell_name.contains("zsh") { + vec!["-l".into(), "-i".into(), "-c".into(), command.into()] } else { vec!["-l".into(), "-c".into(), command.into()] } diff --git a/packages/tauri-app/src-tauri/tauri.conf.json b/packages/tauri-app/src-tauri/tauri.conf.json index 86cd4913..188f2178 100644 --- a/packages/tauri-app/src-tauri/tauri.conf.json +++ b/packages/tauri-app/src-tauri/tauri.conf.json @@ -43,11 +43,6 @@ "bundle": { "active": true, "linux": { - "appimage": { - "files": { - "/usr/share/applications/ai.neuralnomads.codenomad.client.desktop": "icons/linux/ai.neuralnomads.codenomad.client.desktop" - } - }, "deb": { "files": { "/usr/share/applications/ai.neuralnomads.codenomad.client.desktop": "icons/linux/ai.neuralnomads.codenomad.client.desktop",