diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..2898d23 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,71 @@ +name: Bug Report +description: Report a bug or regression in CodeNomad +labels: + - bug +title: "[Bug]: " +body: + - type: markdown + attributes: + value: | + Thanks for filing a bug report! Please review open issues before submitting a new one and provide as much detail as possible so we can reproduce the problem. + - type: dropdown + id: variant + attributes: + label: App Variant + description: Which build are you running when this issue appears? + multiple: false + options: + - Electron + - Tauri + - Server CLI + validations: + required: true + - type: input + id: os-version + attributes: + label: Operating System & Version + description: Include the OS family and version (e.g., macOS 15.0, Ubuntu 24.04, Windows 11 23H2). + placeholder: macOS 15.0 + validations: + required: true + - type: input + id: summary + attributes: + label: Issue Summary + description: Briefly describe what is happening. + placeholder: A quick one sentence problem statement + validations: + required: true + - type: textarea + id: repro + attributes: + label: Steps to Reproduce + description: List the steps needed to reproduce the problem. + placeholder: | + 1. Go to ... + 2. Click ... + 3. Observe ... + validations: + required: true + - type: textarea + id: expected + attributes: + label: Expected Behavior + description: Describe what you expected to happen instead. + validations: + required: true + - type: textarea + id: logs + attributes: + label: Logs & Screenshots + description: Attach relevant logs, stack traces, or screenshots if available. + placeholder: Paste logs here or drag-and-drop files onto the issue. + validations: + required: false + - type: textarea + id: extra + attributes: + label: Additional Context + description: Add any other context about the problem here. + validations: + required: false diff --git a/.github/workflows/build-and-upload.yml b/.github/workflows/build-and-upload.yml new file mode 100644 index 0000000..0f01652 --- /dev/null +++ b/.github/workflows/build-and-upload.yml @@ -0,0 +1,519 @@ +name: Build and Upload Binaries + +on: + workflow_call: + inputs: + version: + description: "Version to apply to workspace packages" + required: true + type: string + tag: + description: "Git tag to upload assets to" + required: true + type: string + release_name: + description: "Release name (unused here, for context)" + required: true + type: string + +permissions: + id-token: write + contents: write + +env: + NODE_VERSION: 20 + +jobs: + build-macos: + runs-on: macos-15-intel + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VERSION: ${{ inputs.version }} + TAG: ${{ inputs.tag }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: npm + + - name: Set workspace versions + run: npm version ${VERSION} --workspaces --include-workspace-root --no-git-tag-version --allow-same-version + + - name: Install dependencies + run: npm ci --workspaces + + - name: Ensure rollup native binary + run: npm install @rollup/rollup-darwin-x64 --no-save + + - name: Build macOS binaries (Electron) + run: npm run build:mac --workspace @neuralnomads/codenomad-electron-app + + - name: Upload release assets + run: | + set -euo pipefail + shopt -s nullglob + for file in packages/electron-app/release/*.zip; do + [ -f "$file" ] || continue + echo "Uploading $file" + gh release upload "$TAG" "$file" --clobber + done + + build-windows: + runs-on: windows-2025 + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VERSION: ${{ inputs.version }} + TAG: ${{ inputs.tag }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: npm + + - name: Set workspace versions + run: npm version ${{ env.VERSION }} --workspaces --include-workspace-root --no-git-tag-version --allow-same-version + shell: bash + + - name: Install dependencies + run: npm ci --workspaces + + - name: Ensure rollup native binary + run: npm install @rollup/rollup-win32-x64-msvc --no-save + + - name: Build Windows binaries (Electron) + run: npm run build:win --workspace @neuralnomads/codenomad-electron-app + + - name: Upload release assets + shell: pwsh + run: | + Get-ChildItem -Path "packages/electron-app/release" -Filter *.zip -File | ForEach-Object { + Write-Host "Uploading $($_.FullName)" + gh release upload $env:TAG $_.FullName --clobber + } + + build-linux: + runs-on: ubuntu-24.04 + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VERSION: ${{ inputs.version }} + TAG: ${{ inputs.tag }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: npm + + - name: Set workspace versions + run: npm version ${VERSION} --workspaces --include-workspace-root --no-git-tag-version --allow-same-version + + - name: Install dependencies + run: npm ci --workspaces + + - name: Ensure rollup native binary + run: npm install @rollup/rollup-linux-x64-gnu --no-save + + - name: Build Linux binaries (Electron) + run: npm run build:linux --workspace @neuralnomads/codenomad-electron-app + + - name: Upload release assets + run: | + set -euo pipefail + shopt -s nullglob + for file in packages/electron-app/release/*.zip; do + [ -f "$file" ] || continue + echo "Uploading $file" + gh release upload "$TAG" "$file" --clobber + done + + build-tauri-macos: + runs-on: macos-15-intel + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VERSION: ${{ inputs.version }} + TAG: ${{ inputs.tag }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: npm + + - name: Setup Rust (Tauri) + uses: dtolnay/rust-toolchain@stable + + - name: Set workspace versions + run: npm version ${VERSION} --workspaces --include-workspace-root --no-git-tag-version --allow-same-version + + - name: Install dependencies + run: npm ci --workspaces + + - name: Ensure rollup native binary + run: npm install @rollup/rollup-darwin-x64 --no-save + + - name: Build macOS bundle (Tauri) + run: npm run build --workspace @codenomad/tauri-app + + - name: Package Tauri artifacts (macOS) + run: | + set -euo pipefail + BUNDLE_ROOT="packages/tauri-app/target/release/bundle" + ARTIFACT_DIR="packages/tauri-app/release-tauri" + rm -rf "$ARTIFACT_DIR" + mkdir -p "$ARTIFACT_DIR" + if [ -d "$BUNDLE_ROOT/macos/CodeNomad.app" ]; then + ditto -ck --sequesterRsrc --keepParent "$BUNDLE_ROOT/macos/CodeNomad.app" "$ARTIFACT_DIR/CodeNomad-Tauri-${VERSION}-macos-x64.zip" + fi + + - name: Upload Tauri release assets (macOS) + run: | + set -euo pipefail + shopt -s nullglob + for file in packages/tauri-app/release-tauri/*.zip; do + [ -f "$file" ] || continue + echo "Uploading $file" + gh release upload "$TAG" "$file" --clobber + done + + build-tauri-macos-arm64: + runs-on: macos-26 + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VERSION: ${{ inputs.version }} + TAG: ${{ inputs.tag }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: npm + + - name: Setup Rust (Tauri) + uses: dtolnay/rust-toolchain@stable + + - name: Set workspace versions + run: npm version ${VERSION} --workspaces --include-workspace-root --no-git-tag-version --allow-same-version + + - name: Install dependencies + run: npm ci --workspaces + + - name: Ensure rollup native binary + run: npm install @rollup/rollup-darwin-arm64 --no-save + + - name: Build macOS bundle (Tauri, arm64) + run: npm run build --workspace @codenomad/tauri-app + + - name: Package Tauri artifacts (macOS arm64) + run: | + set -euo pipefail + BUNDLE_ROOT="packages/tauri-app/target/release/bundle" + ARTIFACT_DIR="packages/tauri-app/release-tauri" + rm -rf "$ARTIFACT_DIR" + mkdir -p "$ARTIFACT_DIR" + if [ -d "$BUNDLE_ROOT/macos/CodeNomad.app" ]; then + ditto -ck --sequesterRsrc --keepParent "$BUNDLE_ROOT/macos/CodeNomad.app" "$ARTIFACT_DIR/CodeNomad-Tauri-${VERSION}-macos-arm64.zip" + fi + + - name: Upload Tauri release assets (macOS arm64) + run: | + set -euo pipefail + shopt -s nullglob + for file in packages/tauri-app/release-tauri/*.zip; do + [ -f "$file" ] || continue + echo "Uploading $file" + gh release upload "$TAG" "$file" --clobber + done + + build-tauri-windows: + runs-on: windows-2025 + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VERSION: ${{ inputs.version }} + TAG: ${{ inputs.tag }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: npm + + - name: Setup Rust (Tauri) + uses: dtolnay/rust-toolchain@stable + + - name: Set workspace versions + run: npm version ${{ env.VERSION }} --workspaces --include-workspace-root --no-git-tag-version --allow-same-version + shell: bash + + - name: Install dependencies + run: npm ci --workspaces + + - name: Ensure rollup native binary + run: npm install @rollup/rollup-win32-x64-msvc --no-save + + - name: Build Windows bundle (Tauri) + run: npm run build --workspace @codenomad/tauri-app + + - name: Package Tauri artifacts (Windows) + shell: pwsh + run: | + $bundleRoot = "packages/tauri-app/target/release/bundle" + $artifactDir = "packages/tauri-app/release-tauri" + if (Test-Path $artifactDir) { Remove-Item $artifactDir -Recurse -Force } + New-Item -ItemType Directory -Path $artifactDir | Out-Null + $exe = Get-ChildItem -Path $bundleRoot -Recurse -File -Filter *.exe | Select-Object -First 1 + if ($null -ne $exe) { + $dest = Join-Path $artifactDir ("CodeNomad-Tauri-$env:VERSION-windows-x64.zip") + Compress-Archive -Path $exe.Directory.FullName -DestinationPath $dest -Force + } + + - name: Upload Tauri release assets (Windows) + shell: pwsh + run: | + if (Test-Path "packages/tauri-app/release-tauri") { + Get-ChildItem -Path "packages/tauri-app/release-tauri" -Filter *.zip -File | ForEach-Object { + Write-Host "Uploading $($_.FullName)" + gh release upload $env:TAG $_.FullName --clobber + } + } + + build-tauri-linux: + runs-on: ubuntu-24.04 + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VERSION: ${{ inputs.version }} + TAG: ${{ inputs.tag }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: npm + + - name: Setup Rust (Tauri) + uses: dtolnay/rust-toolchain@stable + + - name: Install Linux build dependencies (Tauri) + run: | + sudo apt-get update + sudo apt-get install -y \ + build-essential \ + pkg-config \ + libgtk-3-dev \ + libglib2.0-dev \ + libwebkit2gtk-4.1-dev \ + libsoup-3.0-dev \ + libayatana-appindicator3-dev \ + librsvg2-dev + + - name: Set workspace versions + run: npm version ${VERSION} --workspaces --include-workspace-root --no-git-tag-version --allow-same-version + + - name: Install dependencies + run: npm ci --workspaces + + - name: Ensure rollup native binary + run: npm install @rollup/rollup-linux-x64-gnu --no-save + + - name: Build Linux bundle (Tauri) + run: npm run build --workspace @codenomad/tauri-app + + - name: Package Tauri artifacts (Linux) + run: | + set -euo pipefail + SEARCH_ROOT="packages/tauri-app/target" + ARTIFACT_DIR="packages/tauri-app/release-tauri" + rm -rf "$ARTIFACT_DIR" + mkdir -p "$ARTIFACT_DIR" + shopt -s nullglob globstar + + find_one() { + find "$SEARCH_ROOT" -type f -iname "$1" | head -n1 + } + + appimage=$(find_one "*.AppImage") + deb=$(find_one "*.deb") + rpm=$(find_one "*.rpm") + + if [ -z "$appimage" ] || [ -z "$deb" ] || [ -z "$rpm" ]; then + echo "Missing bundle(s): appimage=${appimage:-none} deb=${deb:-none} rpm=${rpm:-none}" >&2 + exit 1 + fi + + cp "$appimage" "$ARTIFACT_DIR/CodeNomad-Tauri-${VERSION}-linux-x64.AppImage" + cp "$deb" "$ARTIFACT_DIR/CodeNomad-Tauri-${VERSION}-linux-x64.deb" + cp "$rpm" "$ARTIFACT_DIR/CodeNomad-Tauri-${VERSION}-linux-x64.rpm" + + - name: Upload Tauri release assets (Linux) + run: | + set -euo pipefail + shopt -s nullglob + for file in packages/tauri-app/release-tauri/*; do + [ -f "$file" ] || continue + echo "Uploading $file" + gh release upload "$TAG" "$file" --clobber + done + + build-tauri-linux-arm64: + if: ${{ false }} + runs-on: ubuntu-24.04 + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VERSION: ${{ inputs.version }} + TAG: ${{ inputs.tag }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup QEMU + uses: docker/setup-qemu-action@v3 + with: + platforms: linux/arm64 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: npm + + - name: Setup Rust (Tauri) + uses: dtolnay/rust-toolchain@stable + with: + targets: aarch64-unknown-linux-gnu + + - name: Install Linux build dependencies (Tauri) + run: | + sudo dpkg --add-architecture arm64 + sudo tee /etc/apt/sources.list.d/arm64.list >/dev/null <<'EOF' + deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports noble main restricted universe multiverse + deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports noble-updates main restricted universe multiverse + deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports noble-security main restricted universe multiverse + deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports noble-backports main restricted universe multiverse + EOF + sudo apt-get update + sudo apt-get install -y \ + build-essential \ + pkg-config \ + gcc-aarch64-linux-gnu \ + g++-aarch64-linux-gnu \ + libgtk-3-dev:arm64 \ + libglib2.0-dev:arm64 \ + libwebkit2gtk-4.1-dev:arm64 \ + libsoup-3.0-dev:arm64 \ + libayatana-appindicator3-dev:arm64 \ + librsvg2-dev:arm64 + + - name: Set workspace versions + run: npm version ${VERSION} --workspaces --include-workspace-root --no-git-tag-version --allow-same-version + + - name: Install dependencies + run: npm ci --workspaces + + - name: Ensure rollup native binary + run: npm install @rollup/rollup-linux-arm64-gnu --no-save + + - name: Build Linux bundle (Tauri arm64) + env: + TAURI_BUILD_TARGET: aarch64-unknown-linux-gnu + PKG_CONFIG_PATH: /usr/lib/aarch64-linux-gnu/pkgconfig + CC_aarch64_unknown_linux_gnu: aarch64-linux-gnu-gcc + CXX_aarch64_unknown_linux_gnu: aarch64-linux-gnu-g++ + AR_aarch64_unknown_linux_gnu: aarch64-linux-gnu-ar + run: npm run build --workspace @codenomad/tauri-app + + - name: Package Tauri artifacts (Linux arm64) + run: | + set -euo pipefail + SEARCH_ROOT="packages/tauri-app/target" + ARTIFACT_DIR="packages/tauri-app/release-tauri" + rm -rf "$ARTIFACT_DIR" + mkdir -p "$ARTIFACT_DIR" + shopt -s nullglob globstar + first_artifact=$(find "$SEARCH_ROOT" -type f \( -name "*.AppImage" -o -name "*.deb" -o -name "*.rpm" -o -name "*.tar.gz" \) | head -n1) + fallback_bin="$SEARCH_ROOT/release/codenomad-tauri" + if [ -n "$first_artifact" ]; then + zip -j "$ARTIFACT_DIR/CodeNomad-Tauri-${VERSION}-linux-x64.zip" "$first_artifact" + elif [ -f "$fallback_bin" ]; then + zip -j "$ARTIFACT_DIR/CodeNomad-Tauri-${VERSION}-linux-x64.zip" "$fallback_bin" + else + echo "No bundled artifact found under $SEARCH_ROOT and no binary at $fallback_bin" >&2 + exit 1 + fi + + + - name: Upload Tauri release assets (Linux arm64) + run: | + set -euo pipefail + shopt -s nullglob + for file in packages/tauri-app/release-tauri/*.zip; do + [ -f "$file" ] || continue + echo "Uploading $file" + gh release upload "$TAG" "$file" --clobber + done + + + build-linux-rpm: + runs-on: ubuntu-24.04 + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VERSION: ${{ inputs.version }} + TAG: ${{ inputs.tag }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: npm + + - name: Install rpm packaging dependencies + run: | + sudo apt-get update + sudo apt-get install -y rpm ruby ruby-dev build-essential + sudo gem install --no-document fpm + + - name: Set workspace versions + run: npm version ${VERSION} --workspaces --include-workspace-root --no-git-tag-version --allow-same-version + + - name: Install project dependencies + run: npm ci --workspaces + + - name: Ensure rollup native binary + run: npm install @rollup/rollup-linux-x64-gnu --no-save + + - name: Build Linux RPM binaries + run: npm run build:linux-rpm --workspace @neuralnomads/codenomad-electron-app + + - name: Upload RPM release assets + run: | + set -euo pipefail + shopt -s nullglob + for file in packages/electron-app/release/*.rpm; do + [ -f "$file" ] || continue + echo "Uploading $file" + gh release upload "$TAG" "$file" --clobber + done diff --git a/.github/workflows/dev-release.yml b/.github/workflows/dev-release.yml new file mode 100644 index 0000000..aa24529 --- /dev/null +++ b/.github/workflows/dev-release.yml @@ -0,0 +1,16 @@ +name: Dev Release + +on: + workflow_dispatch: + +permissions: + id-token: write + contents: write + +jobs: + dev-release: + uses: ./.github/workflows/reusable-release.yml + with: + version_suffix: -dev + dist_tag: dev + secrets: inherit diff --git a/.github/workflows/manual-npm-publish.yml b/.github/workflows/manual-npm-publish.yml new file mode 100644 index 0000000..86b8768 --- /dev/null +++ b/.github/workflows/manual-npm-publish.yml @@ -0,0 +1,74 @@ +name: Manual NPM Publish + +on: + workflow_dispatch: + inputs: + version: + description: "Version to publish (e.g. 0.2.0-dev)" + required: false + type: string + dist_tag: + description: "npm dist-tag" + required: false + default: dev + type: string + workflow_call: + inputs: + version: + required: true + type: string + dist_tag: + required: false + type: string + default: dev + +permissions: + contents: read + id-token: write + +jobs: + publish: + runs-on: ubuntu-latest + env: + NODE_VERSION: 20 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + registry-url: https://registry.npmjs.org + + - name: Ensure npm >=11.5.1 + run: npm install -g npm@latest + + - name: Install dependencies + run: npm ci --workspaces + + - name: Ensure rollup native binary + run: npm install @rollup/rollup-linux-x64-gnu --no-save + + - name: Build server package (includes UI bundling) + run: npm run build --workspace @neuralnomads/codenomad + + - name: Set publish metadata + shell: bash + run: | + VERSION_INPUT="${{ inputs.version }}" + if [ -z "$VERSION_INPUT" ]; then + VERSION_INPUT=$(node -p "require('./package.json').version") + fi + echo "VERSION=$VERSION_INPUT" >> "$GITHUB_ENV" + echo "DIST_TAG=${{ inputs.dist_tag || 'dev' }}" >> "$GITHUB_ENV" + + - name: Bump package version for publish + run: npm version ${VERSION} --workspaces --include-workspace-root --no-git-tag-version --allow-same-version + + - name: Publish server package with provenance + env: + NPM_CONFIG_PROVENANCE: true + NPM_CONFIG_REGISTRY: https://registry.npmjs.org + run: | + npm publish --workspace @neuralnomads/codenomad --access public --tag ${DIST_TAG} --provenance diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..dfd07e8 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,17 @@ +name: Release Binaries + +on: + push: + branches: + - main + +permissions: + id-token: write + contents: write + +jobs: + release: + uses: ./.github/workflows/reusable-release.yml + with: + dist_tag: latest + secrets: inherit diff --git a/.github/workflows/reusable-release.yml b/.github/workflows/reusable-release.yml new file mode 100644 index 0000000..026fd8f --- /dev/null +++ b/.github/workflows/reusable-release.yml @@ -0,0 +1,80 @@ +name: Reusable Release + +on: + workflow_call: + inputs: + version_suffix: + description: "Suffix appended to package.json version" + required: false + default: "" + type: string + dist_tag: + description: "npm dist-tag to publish under" + required: false + default: dev + type: string + +permissions: + id-token: write + contents: write + +env: + NODE_VERSION: 20 + +jobs: + prepare-release: + runs-on: ubuntu-latest + outputs: + version: ${{ steps.versions.outputs.version }} + tag: ${{ steps.versions.outputs.tag }} + release_name: ${{ steps.versions.outputs.release_name }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + + - name: Compute release versions + id: versions + env: + VERSION_SUFFIX: ${{ inputs.version_suffix }} + run: | + BASE_VERSION=$(node -p "require('./package.json').version") + VERSION="${BASE_VERSION}${VERSION_SUFFIX}" + TAG="v${VERSION}" + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + echo "tag=$TAG" >> "$GITHUB_OUTPUT" + echo "release_name=$TAG" >> "$GITHUB_OUTPUT" + + - name: Create GitHub release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG: ${{ steps.versions.outputs.tag }} + run: | + if gh release view "$TAG" >/dev/null 2>&1; then + echo "Release $TAG already exists" + else + gh release create "$TAG" --title "$TAG" --generate-notes + fi + + build-and-upload: + needs: prepare-release + uses: ./.github/workflows/build-and-upload.yml + with: + version: ${{ needs.prepare-release.outputs.version }} + tag: ${{ needs.prepare-release.outputs.tag }} + release_name: ${{ needs.prepare-release.outputs.release_name }} + secrets: inherit + + publish-server: + needs: + - prepare-release + - build-and-upload + uses: ./.github/workflows/manual-npm-publish.yml + with: + version: ${{ needs.prepare-release.outputs.version }} + dist_tag: ${{ inputs.dist_tag }} + secrets: inherit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3963666 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +node_modules/ +dist/ +release/ +.DS_Store +*.log +.vite/ +.electron-vite/ +out/ +.dir-locals.el \ No newline at end of file diff --git a/.opencode/agent/web_developer.md b/.opencode/agent/web_developer.md new file mode 100644 index 0000000..97e7f80 --- /dev/null +++ b/.opencode/agent/web_developer.md @@ -0,0 +1,5 @@ +--- +description: Develops Web UI components. +mode: all +--- +You are a Web Frontend Developer Agent. Your primary focus is on developing SolidJS UI components, ensuring adherence to modern web best practices, excellent UI/UX, and efficient data integration. diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..3017aae --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,20 @@ +# AGENT NOTES + +## Styling Guidelines +- Reuse the existing token & utility layers before introducing new CSS variables or custom properties. Extend `src/styles/tokens.css` / `src/styles/utilities.css` if a shared pattern is needed. +- Keep aggregate entry files (e.g., `src/styles/controls.css`, `messaging.css`, `panels.css`) lean—they should only `@import` feature-specific subfiles located inside `src/styles/{components|messaging|panels}`. +- When adding new component styles, place them beside their peers in the scoped subdirectory (e.g., `src/styles/messaging/new-part.css`) and import them from the corresponding aggregator file. +- Prefer smaller, focused style files (≈150 lines or less) over large monoliths. Split by component or feature area if a file grows beyond that size. +- Co-locate reusable UI patterns (buttons, selectors, dropdowns, etc.) under `src/styles/components/` and avoid redefining the same utility classes elsewhere. +- Document any new styling conventions or directory additions in this file so future changes remain consistent. + +## Coding Principles +- Favor KISS by keeping modules narrowly scoped and limiting public APIs to what callers actually need. +- Uphold DRY: share helpers via dedicated modules before copy/pasting logic across stores, components, or scripts. +- Enforce single responsibility; split large files when concerns diverge (state, actions, API, events, etc.). +- Prefer composable primitives (signals, hooks, utilities) over deep inheritance or implicit global state. +- When adding platform integrations (SSE, IPC, SDK), isolate them in thin adapters that surface typed events/actions. + +## Tooling Preferences +- Use the `edit` tool for modifying existing files; prefer it over other editing methods. +- Use the `write` tool only when creating new files from scratch. diff --git a/BUILD.md b/BUILD.md new file mode 100644 index 0000000..0ae1909 --- /dev/null +++ b/BUILD.md @@ -0,0 +1,263 @@ +# Building CodeNomad Binaries + +This guide explains how to build distributable binaries for CodeNomad. + +## Prerequisites + +- **Bun** - Package manager and runtime +- **Node.js** - For electron-builder +- **Electron Builder** - Installed via devDependencies + +## Quick Start + +All commands now run inside the workspace packages. From the repo root you can target the Electron app package directly: + +```bash +npm run build --workspace @neuralnomads/codenomad-electron-app +``` + +### Build for Current Platform (macOS default) + +```bash +bun run build:binaries +``` + +This builds for macOS (Universal - Intel + Apple Silicon) by default. + +## Platform-Specific Builds + +### macOS + +```bash +# Universal (Intel + Apple Silicon) - Recommended +bun run build:mac + +# Intel only (x64) +bun run build:mac-x64 + +# Apple Silicon only (ARM64) +bun run build:mac-arm64 +``` + +**Output formats:** `.dmg`, `.zip` + +### Windows + +```bash +# x64 (64-bit Intel/AMD) +bun run build:win + +# ARM64 (Windows on ARM) +bun run build:win-arm64 +``` + +**Output formats:** `.exe` (NSIS installer), `.zip` + +### Linux + +```bash +# x64 (64-bit) +bun run build:linux + +# ARM64 +bun run build:linux-arm64 +``` + +**Output formats:** `.AppImage`, `.deb`, `.tar.gz` + +### Build All Platforms + +```bash +bun run build:all +``` + +⚠️ **Note:** Cross-platform builds may have limitations. Build on the target platform for best results. + +## Build Process + +The build script performs these steps: + +1. **Build @neuralnomads/codenomad** → Produces the CLI `dist/` bundle (also rebuilds the UI assets it serves) +2. **Compile TypeScript + bundle with Vite** → Electron main, preload, and renderer output in `dist/` +3. **Package with electron-builder** → Platform-specific binaries + +## Output + +Binaries are generated in the `release/` directory: + +``` +release/ +├── CodeNomad-0.1.0-mac-universal.dmg +├── CodeNomad-0.1.0-mac-universal.zip +├── CodeNomad-0.1.0-win-x64.exe +├── CodeNomad-0.1.0-linux-x64.AppImage +└── ... +``` + +## File Naming Convention + +``` +CodeNomad-{version}-{os}-{arch}.{ext} +``` + +- **version**: From package.json (e.g., `0.1.0`) +- **os**: `mac`, `win`, `linux` +- **arch**: `x64`, `arm64`, `universal` +- **ext**: `dmg`, `zip`, `exe`, `AppImage`, `deb`, `tar.gz` + +## Platform Requirements + +### macOS + +- **Build on:** macOS 10.13+ +- **Run on:** macOS 10.13+ +- **Code signing:** Optional (recommended for distribution) + +### Windows + +- **Build on:** Windows 10+, macOS, or Linux +- **Run on:** Windows 10+ +- **Code signing:** Optional (recommended for distribution) + +### Linux + +- **Build on:** Any platform +- **Run on:** Ubuntu 18.04+, Debian 10+, Fedora 32+, Arch +- **Dependencies:** Varies by distro + +## Troubleshooting + +### Build fails on macOS + +```bash +# Install Xcode Command Line Tools +xcode-select --install +``` + +### Build fails on Linux + +```bash +# Install dependencies (Debian/Ubuntu) +sudo apt-get install -y rpm + +# Install dependencies (Fedora) +sudo dnf install -y rpm-build +``` + +### "electron-builder not found" + +```bash +# Install dependencies +bun install +``` + +### Build is slow + +- Use platform-specific builds instead of `build:all` +- Close other applications to free up resources +- Use SSD for faster I/O + +## Development vs Production + +**Development:** + +```bash +bun run dev # Hot reload, no packaging +``` + +**Production:** + +```bash +bun run build:binaries # Full build + packaging +``` + +## CI/CD Integration + +Example GitHub Actions workflow: + +```yaml +name: Build Binaries + +on: + push: + tags: + - "v*" + +jobs: + build-mac: + runs-on: macos-latest + steps: + - uses: actions/checkout@v3 + - uses: oven-sh/setup-bun@v1 + - run: bun install + - run: bun run build:mac + + build-win: + runs-on: windows-latest + steps: + - uses: actions/checkout@v3 + - uses: oven-sh/setup-bun@v1 + - run: bun install + - run: bun run build:win + + build-linux: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: oven-sh/setup-bun@v1 + - run: bun install + - run: bun run build:linux +``` + +## Advanced Configuration + +Edit `package.json` → `build` section to customize: + +- App icon +- Code signing +- Installer options +- File associations +- Auto-update settings + +See [electron-builder docs](https://www.electron.build/) for details. + +## Brand Assets + +- `images/CodeNomad-Icon.png` — primary asset for in-app logo placements and the 1024×1024 master icon used to generate packaged app icons + +To update the binaries: + +1. Run `node scripts/generate-icons.js images/CodeNomad-Icon.png electron/resources` to round the corners and emit fresh `icon.icns`, `icon.ico`, and `icon.png` files. +2. (Optional) Pass `--radius` to tweak the corner curvature or `--name` to change the filename prefix. +3. If you prefer manual control, export `images/CodeNomad-Icon.png` with your tool of choice and place the generated files in `electron/resources/`. + +## Clean Build + +Remove previous builds: + +```bash +rm -rf release/ dist/ +bun run build:binaries +``` + +## FAQ + +**Q: Can I build for Windows on macOS?** +A: Yes, but native binaries (e.g., DMG) require the target OS. + +**Q: How large are the binaries?** +A: Approximately 100-150 MB (includes Electron runtime). + +**Q: Do I need code signing?** +A: Not required, but recommended for public distribution to avoid security warnings. + +**Q: How do I update the version?** +A: Update `version` in `package.json`, then rebuild. + +## Support + +For issues or questions: + +- Check [electron-builder documentation](https://www.electron.build/) +- Open an issue in the repository +- Review existing build logs in `release/` diff --git a/PROGRESS.md b/PROGRESS.md new file mode 100644 index 0000000..cce670b --- /dev/null +++ b/PROGRESS.md @@ -0,0 +1,149 @@ +# CodeNomad - Development Progress + +## Completed Tasks + +### Task 001: Project Setup ✅ +- Set up Electron + SolidJS + Vite + TypeScript +- Configured TailwindCSS v3 (downgraded from v4 for electron-vite compatibility) +- Build pipeline with electron-vite +- Application window management +- Application menu with keyboard shortcuts + +### Task 002: Empty State UI & Folder Selection ✅ +- Empty state component with styled UI +- Native folder picker integration +- IPC handlers for folder selection +- UI state management with SolidJS signals +- Loading states with spinner +- Keyboard shortcuts (Cmd/Ctrl+N) + +### Task 003: Process Manager ✅ +- Process spawning: `opencode serve --port 0` +- Port detection from stdout (regex: `opencode server listening on http://...`) +- Process lifecycle management (spawn, kill, cleanup) +- IPC communication for instance management +- Instance state tracking (starting → ready → stopped/error) +- Auto-cleanup on app quit +- Error handling & timeout protection (10s) +- Graceful shutdown (SIGTERM → SIGKILL) + +### Task 004: SDK Integration ✅ +- Installed `@opencode-ai/sdk` package +- SDK manager for client lifecycle +- Session fetching from OpenCode server +- Agent fetching (`client.app.agents()`) +- Provider fetching (`client.config.providers()`) +- Session store with SolidJS signals +- Instance store updated with SDK client +- Loading states for async operations +- Error handling for network failures + +### Task 005: Session Picker Modal ✅ +- Modal dialog with Kobalte Dialog +- Lists ALL existing sessions (scrollable) +- Session metadata display (title, relative timestamp) +- Native HTML select dropdown for agents +- Auto-selects first agent by default +- Create new session with selected agent +- Cancel button stops instance and closes modal +- Resume session on click +- Empty state for no sessions +- Loading state for agents +- Keyboard navigation (Escape to cancel) + +## Current State + +**Working Features:** +- ✅ App launches with empty state +- ✅ Folder selection via native dialog +- ✅ OpenCode server spawning per folder +- ✅ Port extraction and process tracking +- ✅ SDK client connection to running servers +- ✅ Session list fetching and display +- ✅ Agent and provider data fetching +- ✅ Session picker modal on instance creation +- ✅ Resume existing sessions +- ✅ Create new sessions with agent selection + +**File Structure:** +``` +packages/opencode-client/ +├── electron/ +│ ├── main/ +│ │ ├── main.ts (window + IPC setup) +│ │ ├── menu.ts (app menu) +│ │ ├── ipc.ts (instance IPC handlers) +│ │ └── process-manager.ts (server spawning) +│ └── preload/ +│ └── index.ts (IPC bridge) +├── src/ +│ ├── components/ +│ │ ├── empty-state.tsx +│ │ └── session-picker.tsx +│ ├── lib/ +│ │ └── sdk-manager.ts +│ ├── stores/ +│ │ ├── ui.ts +│ │ ├── instances.ts +│ │ └── sessions.ts +│ ├── types/ +│ │ ├── electron.d.ts +│ │ ├── instance.ts +│ │ └── session.ts +│ └── App.tsx +├── tasks/ +│ ├── done/ (001-005) +│ └── todo/ (006+) +└── docs/ +``` + +## Next Steps + +### Task 006: Message Stream UI (NEXT) +- Message display component +- User/assistant message rendering +- Markdown support with syntax highlighting +- Tool use visualization +- Auto-scroll behavior + +### Task 007: Prompt Input +- Text input with multi-line support +- Send button +- File attachment support +- Keyboard shortcuts (Enter for new line; Cmd+Enter/Ctrl+Enter to send) + +### Task 008: Instance Tabs +- Tab bar for multiple instances +- Switch between instances +- Close instance tabs +- "+" button for new instance + +## Build & Test + +```bash +cd packages/opencode-client +bun run build +bunx electron . +``` + +**Known Issue:** +- Dev mode (`bun dev`) fails due to Bun workspace hoisting + electron-vite +- Workaround: Use production builds for testing + +## Dependencies + +- Electron 38 +- SolidJS 1.8 +- TailwindCSS 3.x +- @opencode-ai/sdk +- @kobalte/core (Dialog) +- Vite 5 +- TypeScript 5 + +## Stats + +- **Tasks completed:** 5/5 (Phase 1) +- **Files created:** 18+ +- **Lines of code:** ~1500+ +- **Build time:** ~7s +- **Bundle size:** 152KB (renderer) diff --git a/dev-docs/INDEX.md b/dev-docs/INDEX.md new file mode 100644 index 0000000..290f7f7 --- /dev/null +++ b/dev-docs/INDEX.md @@ -0,0 +1,180 @@ +# Documentation Index + +Quick reference to all documentation files. + +## Main Documents + +### [README.md](../README.md) + +Project overview, installation, and getting started guide. + +### [SUMMARY.md](SUMMARY.md) + +Executive summary of the entire project - **start here!** + +### [MVP-PRINCIPLES.md](MVP-PRINCIPLES.md) + +**MVP development philosophy** - Focus on functionality, NOT performance ⚡ + +--- + +## Specification Documents + +### [architecture.md](architecture.md) + +**Complete system architecture** + +- Component layers and responsibilities +- State management structure +- Data flow diagrams +- Technology stack +- Security and performance considerations + +**Read this to understand:** How the app is structured + +### [user-interface.md](user-interface.md) + +**Complete UI/UX specifications** + +- Every screen and component layout +- Visual design specifications +- Interaction patterns +- Accessibility requirements +- Color schemes and typography + +**Read this to understand:** What the app looks like and how users interact + +### [technical-implementation.md](technical-implementation.md) + +**Implementation details** + +- File structure +- TypeScript interfaces +- Process management logic +- SDK integration patterns +- IPC communication +- Error handling strategies + +**Read this to understand:** How to actually build it + +### [build-roadmap.md](build-roadmap.md) + +**Development plan** + +- 8 phases of development +- Task dependencies +- Timeline estimates +- Success criteria +- Risk mitigation + +**Read this to understand:** The development journey from start to finish + +--- + +## Task Documents + +### [tasks/README.md](../tasks/README.md) + +**Task management guide** + +- Task workflow +- Naming conventions +- How to work on tasks +- Progress tracking + +### Task Files (in tasks/todo/) + +- **001-project-setup.md** - Electron + SolidJS boilerplate +- **002-empty-state-ui.md** - Initial UI with folder selection +- **003-process-manager.md** - OpenCode server spawning +- **004-sdk-integration.md** - API client integration +- **005-session-picker-modal.md** - Session selection UI + +More tasks will be added as we progress through phases. + +--- + +## Reading Order + +### For First-Time Readers: + +1. [SUMMARY.md](SUMMARY.md) - Get the big picture +2. [architecture.md](architecture.md) - Understand the structure +3. [user-interface.md](user-interface.md) - See what you're building +4. [build-roadmap.md](build-roadmap.md) - Understand the plan +5. [tasks/README.md](../tasks/README.md) - Learn the workflow + +### For Implementers: + +1. [tasks/README.md](../tasks/README.md) - Understand task workflow +2. [technical-implementation.md](technical-implementation.md) - Implementation patterns +3. [tasks/todo/001-\*.md](../tasks/todo/) - Start with first task +4. Refer to architecture.md and user-interface.md as needed + +### For Designers: + +1. [user-interface.md](user-interface.md) - Complete UI specs +2. [architecture.md](architecture.md) - Component structure +3. [SUMMARY.md](SUMMARY.md) - Feature overview + +### For Project Managers: + +1. [SUMMARY.md](SUMMARY.md) - Executive overview +2. [build-roadmap.md](build-roadmap.md) - Timeline and phases +3. [tasks/README.md](../tasks/README.md) - Task tracking + +--- + +## Quick Reference + +### Common Questions + +**Q: Where do I start?** +A: Read [SUMMARY.md](SUMMARY.md), then start [Task 001](../tasks/todo/001-project-setup.md) + +**Q: How long will this take?** +A: See [build-roadmap.md](build-roadmap.md) - MVP in 3-7 weeks depending on commitment + +**Q: What does the UI look like?** +A: See [user-interface.md](user-interface.md) for complete specifications + +**Q: How does it work internally?** +A: See [architecture.md](architecture.md) for system design + +**Q: How do I build feature X?** +A: See [technical-implementation.md](technical-implementation.md) for patterns + +**Q: What's the development plan?** +A: See [build-roadmap.md](build-roadmap.md) for phases + +--- + +## Document Status + +| Document | Status | Last Updated | +| --------------------------- | ----------- | ------------ | +| README.md | ✅ Complete | 2024-10-22 | +| SUMMARY.md | ✅ Complete | 2024-10-22 | +| architecture.md | ✅ Complete | 2024-10-22 | +| user-interface.md | ✅ Complete | 2024-10-22 | +| technical-implementation.md | ✅ Complete | 2024-10-22 | +| build-roadmap.md | ✅ Complete | 2024-10-22 | +| tasks/README.md | ✅ Complete | 2024-10-22 | +| Task 001-005 | ✅ Complete | 2024-10-22 | + +**Project phase:** Post-MVP (Phases 1-3 complete; Phase 4 work underway). + +--- + +## Contributing to Documentation + +When updating documentation: + +1. Update the relevant file +2. Update "Last Updated" in this index +3. Update SUMMARY.md if adding major changes +4. Keep consistent formatting and style + +--- + +_This index will be updated as more documentation is added._ diff --git a/dev-docs/MVP-PRINCIPLES.md b/dev-docs/MVP-PRINCIPLES.md new file mode 100644 index 0000000..f16579c --- /dev/null +++ b/dev-docs/MVP-PRINCIPLES.md @@ -0,0 +1,326 @@ +# MVP Development Principles + +## Core Philosophy + +**Focus on functionality, NOT performance.** + +The MVP (Minimum Viable Product) is about proving the concept and getting feedback. Performance optimization comes later, after we validate the product with real users. + +--- + +## What We Care About in MVP + +### ✅ DO Focus On: + +1. **Functionality** + - Does it work? + - Can users complete their tasks? + - Are all core features present? + +2. **Correctness** + - Does it produce correct results? + - Does error handling work? + - Is data persisted properly? + +3. **User Experience** + - Is the UI intuitive? + - Are loading states clear? + - Are error messages helpful? + +4. **Stability** + - Does it crash? + - Can users recover from errors? + - Does it lose data? + +5. **Code Quality** + - Is code readable? + - Are types correct? + - Is it maintainable? + +### ❌ DON'T Focus On: + +1. **Performance Optimization** + - Virtual scrolling + - Message batching + - Lazy loading + - Memory optimization + - Render optimization + +2. **Scalability** + - Handling 1000+ messages + - Multiple instances with 100+ sessions + - Large file attachments + - Massive search indexes + +3. **Advanced Features** + - Plugins + - Advanced search + - Custom themes + - Workspace management + +--- + +## Specific MVP Guidelines + +### Messages & Rendering + +**Simple approach:** + +```typescript +// Just render everything - no virtual scrolling + + {(message) => } + +``` + +**Don't worry about:** + +- Sessions with 500+ messages +- Re-render performance +- Memory usage +- Scroll performance + +**When to optimize:** + +- Post-MVP (Phase 8) +- Only if users report issues +- Based on real-world usage data + +### State Management + +**Simple approach:** + +- Use SolidJS signals directly +- No batching +- No debouncing +- No caching layers + +**Don't worry about:** + +- Update frequency +- Number of reactive dependencies +- State structure optimization + +### Process Management + +**Simple approach:** + +- Spawn servers as needed +- Kill on close +- Basic error handling + +**Don't worry about:** + +- Resource limits (max processes) +- CPU/memory monitoring +- Restart optimization +- Process pooling + +### API Communication + +**Simple approach:** + +- Direct SDK calls +- Basic error handling +- Simple retry (if at all) + +**Don't worry about:** + +- Request batching +- Response caching +- Optimistic updates +- Request deduplication + +--- + +## Decision Framework + +When implementing any feature, ask: + +### Is this optimization needed for MVP? + +**NO if:** + +- It only helps with large datasets +- It only helps with many instances +- It's about speed, not correctness +- Users won't notice the difference +- It adds significant complexity + +**YES if:** + +- Users can't complete basic tasks without it +- App is completely unusable without it +- It prevents data loss +- It's a security requirement + +### Examples + +**Virtual Scrolling:** ❌ NO for MVP + +- MVP users won't have 1000+ message sessions +- Simple list rendering works fine for <100 messages +- Add in Phase 8 if needed + +**Error Handling:** ✅ YES for MVP + +- Users need clear feedback when things fail +- Prevents frustration and data loss +- Core to usability + +**Message Batching:** ❌ NO for MVP + +- SolidJS handles updates efficiently +- Only matters at very high frequency +- Add later if users report lag + +**Session Persistence:** ✅ YES for MVP + +- Users expect sessions to persist +- Losing work is unacceptable +- Core functionality + +--- + +## Testing Approach + +### MVP Testing Focus + +**Test for:** + +- ✅ Correctness (does it work?) +- ✅ Error handling (does it fail gracefully?) +- ✅ Data integrity (is data saved?) +- ✅ User flows (can users complete tasks?) + +**Don't test for:** + +- ❌ Performance benchmarks +- ❌ Load testing +- ❌ Stress testing +- ❌ Scalability limits + +### Acceptable Performance + +For MVP, these are **acceptable:** + +- 100 messages render in 1 second +- UI slightly laggy during heavy streaming +- Memory usage grows with message count +- Multiple instances slow down app + +These become **unacceptable** only if: + +- Users complain +- App becomes unusable +- Basic tasks can't be completed + +--- + +## When to Optimize + +### Post-MVP Triggers + +Add optimization when: + +1. **User Feedback** + - Multiple users report slowness + - Users abandon due to performance + - Performance prevents usage + +2. **Measurable Issues** + - App freezes for >2 seconds + - Memory usage causes crashes + - UI becomes unresponsive + +3. **Phase 8 Reached** + - MVP complete and validated + - User base established + - Performance becomes focus + +### How to Optimize + +When the time comes: + +1. **Measure First** + - Profile actual bottlenecks + - Use real user data + - Identify specific problems + +2. **Target Fixes** + - Fix the specific bottleneck + - Don't over-engineer + - Measure improvement + +3. **Iterate** + - Optimize one thing at a time + - Verify with users + - Stop when "fast enough" + +--- + +## Communication with Users + +### During Alpha/Beta + +**Be honest about performance:** + +- "This is an MVP - expect some slowness with large sessions" +- "We're focused on functionality first" +- "Performance optimization is planned for v1.x" + +**Set expectations:** + +- Works best with <200 messages per session +- Multiple instances may slow things down +- We'll optimize based on your feedback + +### Collecting Feedback + +**Ask about:** + +- ✅ What features are missing? +- ✅ What's confusing? +- ✅ What doesn't work? +- ✅ Is it too slow to use? + +**Don't ask about:** + +- ❌ How many milliseconds for X? +- ❌ Memory usage specifics +- ❌ Benchmark comparisons + +--- + +## Summary + +### The MVP Mantra + +> **Make it work, then make it better, then make it fast.** + +For CodeNomad MVP: + +- **Phase 1-7:** Make it work, make it better +- **Phase 8+:** Make it fast + +### Remember + +- Premature optimization is the root of all evil +- Real users provide better optimization guidance than assumptions +- Functionality > Performance for MVP +- You can't optimize what users don't use + +--- + +## Quick Reference + +**When in doubt, ask:** + +1. Is this feature essential for users to do their job? → Build it +2. Is this optimization essential for the feature to work? → Build it +3. Is this just making it faster/more efficient? → Defer to Phase 8 + +**MVP = Minimum _Viable_ Product** + +- Viable = works and is useful +- Viable ≠ optimized and fast diff --git a/dev-docs/SUMMARY.md b/dev-docs/SUMMARY.md new file mode 100644 index 0000000..253270a --- /dev/null +++ b/dev-docs/SUMMARY.md @@ -0,0 +1,348 @@ +# CodeNomad - Project Summary + +## Current Status + +We have completed the MVP milestones (Phases 1-3) and are now operating in post-MVP mode. Future work prioritizes multi-instance support, advanced input polish, and system integrations outlined in later phases. + +## What We've Created + +A comprehensive specification and task breakdown for building the CodeNomad desktop application. + +## Directory Structure + +``` +packages/opencode-client/ +├── docs/ # Comprehensive documentation +│ ├── architecture.md # System architecture & design +│ ├── user-interface.md # UI/UX specifications +│ ├── technical-implementation.md # Technical details & patterns +│ ├── build-roadmap.md # Phased development plan +│ └── SUMMARY.md # This file +├── tasks/ +│ ├── README.md # Task management guide +│ ├── todo/ # Tasks to implement +│ │ ├── 001-project-setup.md +│ │ ├── 002-empty-state-ui.md +│ │ ├── 003-process-manager.md +│ │ ├── 004-sdk-integration.md +│ │ └── 005-session-picker-modal.md +│ └── done/ # Completed tasks (empty) +└── README.md # Project overview + +``` + +## Documentation Overview + +### 1. Architecture (architecture.md) + +**What it covers:** + +- High-level system design +- Component layers (Main process, Renderer, Communication) +- State management approach +- Tab hierarchy (Instance tabs → Session tabs) +- Data flow for key operations +- Technology stack decisions +- Security considerations + +**Key sections:** + +- Component architecture diagram +- Instance/Session state structures +- Communication patterns (HTTP, SSE) +- Error handling strategies +- Performance considerations + +### 2. User Interface (user-interface.md) + +**What it covers:** + +- Complete UI layout specifications +- Visual design for every component +- Interaction patterns +- Keyboard shortcuts +- Accessibility requirements +- Empty states and error states +- Modal designs + +**Key sections:** + +- Detailed layout wireframes (ASCII art) +- Component-by-component specifications +- Message rendering formats +- Control bar designs +- Modal/overlay specifications +- Color schemes and typography + +### 3. Technical Implementation (technical-implementation.md) + +**What it covers:** + +- Technology stack details +- Project file structure +- State management patterns +- Process management implementation +- SDK integration approach +- SSE event handling +- IPC communication +- Error handling strategies +- Performance optimizations + +**Key sections:** + +- Complete project structure +- TypeScript interfaces +- Process spawning logic +- SDK client management +- Message rendering implementation +- Build and packaging config + +### 4. Build Roadmap (build-roadmap.md) + +**What it covers:** + +- 8 development phases +- Task dependencies +- Timeline estimates +- Success criteria per phase +- Risk mitigation +- Release strategy + +**Phases:** + +1. **Foundation** (Week 1) - Project setup, process management +2. **Core Chat** (Week 2) - Message display, SSE streaming +3. **Essential Features** (Week 3) - Markdown, agents, errors +4. **Multi-Instance** (Week 4) - Multiple projects support +5. **Advanced Input** (Week 5) - Commands, file attachments +6. **Polish** (Week 6) - UX refinements, settings +7. **System Integration** (Week 7) - Native features +8. **Advanced** (Week 8+) - Performance, plugins + +## Task Breakdown + +### Current Tasks (Phase 1) + +**001 - Project Setup** (2-3 hours) + +- Set up Electron + SolidJS + Vite +- Configure TypeScript, TailwindCSS +- Create basic project structure +- Verify build pipeline works + +**002 - Empty State UI** (2-3 hours) + +- Create empty state component +- Implement folder selection dialog +- Add keyboard shortcuts +- Style and test responsiveness + +**003 - Process Manager** (4-5 hours) + +- Spawn OpenCode server processes +- Parse stdout for port extraction +- Kill processes on command +- Handle errors and timeouts +- Auto-cleanup on app quit + +**004 - SDK Integration** (3-4 hours) + +- Create SDK client per instance +- Fetch sessions, agents, models +- Implement session CRUD operations +- Add error handling and retries + +**005 - Session Picker Modal** (3-4 hours) + +- Build modal with session list +- Agent selector for new sessions +- Keyboard navigation +- Loading and error states + +**Total Phase 1 time: ~15-20 hours (2-3 weeks part-time)** + +## Key Design Decisions + +### 1. Two-Level Tabs + +- **Level 1**: Instance tabs (one per project folder) +- **Level 2**: Session tabs (multiple per instance) +- Allows working on multiple projects with multiple conversations each + +### 2. Process Management in Main Process + +- Electron main process spawns servers +- Parses stdout to get port +- IPC sends port to renderer +- Ensures clean shutdown on app quit + +### 3. One SDK Client Per Instance + +- Each instance has its own HTTP client +- Connects to different port (different server) +- Isolated state prevents cross-contamination + +### 4. SolidJS for Reactivity + +- Fine-grained reactivity for SSE updates +- No re-render cascades +- Better performance for real-time updates +- Smaller bundle size than React + +### 5. No Virtual Scrolling or Performance Optimization in MVP + +- Start with simple list rendering +- Don't optimize for large sessions initially +- Focus on functionality, not performance +- Add optimizations in post-MVP phases if needed +- Reduces initial complexity and speeds up development + +### 6. Messages and Tool Calls Inline + +- All activity shows in main message stream +- Tool calls expandable/collapsible +- File changes visible inline +- Single timeline view + +## Implementation Guidelines + +### For Each Task: + +1. Read task file completely +2. Review related documentation +3. Follow steps in order +4. Check off acceptance criteria +5. Test thoroughly +6. Move to done/ when complete + +### Code Standards: + +- TypeScript for everything +- No `any` types +- Descriptive variable names +- Comments for complex logic +- Error handling on all async operations +- Loading states for all network calls + +### Testing Approach: + +- Manual testing at each step +- Test on minimum window size (800x600) +- Test error cases +- Test edge cases (long text, special chars) +- Keyboard navigation verification + +## Next Steps + +### To Start Building: + +1. **Read all documentation** + - Understand architecture + - Review UI specifications + - Study technical approach + +2. **Start with Task 001** + - Set up project structure + - Install dependencies + - Verify build works + +3. **Follow sequential order** + - Each task builds on previous + - Don't skip ahead + - Dependencies matter + +4. **Track progress** + - Update task checkboxes + - Move completed tasks to done/ + - Update roadmap as you go + +### When You Hit Issues: + +1. Review task prerequisites +2. Check documentation for clarification +3. Look at related specs +4. Ask questions on unclear requirements +5. Document blockers and solutions + +## Success Metrics + +### MVP (After Task 015) + +- Can select folder → spawn server → chat +- Messages stream in real-time +- Can switch agents and models +- Tool executions visible +- Basic error handling works +- **Performance is NOT a concern** - focus on functionality + +### Beta (After Task 030) + +- Multi-instance support +- Advanced input (files, commands) +- Polished UX +- Settings and preferences +- Native menus + +### v1.0 (After Task 035) + +- System tray integration +- Auto-updates +- Crash reporting +- Production-ready stability + +## Useful References + +### Within This Project: + +- `README.md` - Project overview and getting started +- `docs/architecture.md` - System design +- `docs/user-interface.md` - UI specifications +- `docs/technical-implementation.md` - Implementation details +- `tasks/README.md` - Task workflow guide + +### External: + +- OpenCode server API: https://opencode.ai/docs/server/ +- Electron docs: https://electronjs.org/docs +- SolidJS docs: https://solidjs.com +- Kobalte UI: https://kobalte.dev + +## Questions to Resolve + +Before starting implementation, clarify: + +1. Exact OpenCode CLI syntax for spawning server +2. Expected stdout format for port extraction +3. SDK package location and version +4. Any platform-specific gotchas +5. Icon and branding assets location + +## Estimated Timeline + +**Conservative estimate (part-time, ~15 hours/week):** + +- Phase 1 (MVP Foundation): 2-3 weeks +- Phase 2 (Core Chat): 2 weeks +- Phase 3 (Essential): 2 weeks +- **MVP Complete: 6-7 weeks** + +**Aggressive estimate (full-time, ~40 hours/week):** + +- Phase 1: 1 week +- Phase 2: 1 week +- Phase 3: 1 week +- **MVP Complete: 3 weeks** + +Add 2-4 weeks for testing, bug fixes, and polish before alpha release. + +## This is a Living Document + +As you build: + +- Update estimates based on actual time +- Add new tasks as needed +- Refine specifications +- Document learnings +- Track blockers and solutions + +Good luck! 🚀 diff --git a/dev-docs/TOOL_CALL_IMPLEMENTATION.md b/dev-docs/TOOL_CALL_IMPLEMENTATION.md new file mode 100644 index 0000000..507159b --- /dev/null +++ b/dev-docs/TOOL_CALL_IMPLEMENTATION.md @@ -0,0 +1,228 @@ +# Tool Call Rendering Implementation + +This document describes how tool calls are rendered in the CodeNomad, following the patterns established in the TUI. + +## Overview + +Each tool type has specialized rendering logic that displays the most relevant information for that tool. This matches the TUI's approach of providing context-specific displays rather than generic input/output dumps. + +## Tool-Specific Rendering + +### 1. **read** - File Reading + +- **Title**: `Read {filename}` +- **Body**: Preview of file content (first 6 lines) from `metadata.preview` +- **Use case**: Shows what file content the assistant is reading + +### 2. **edit** - File Editing + +- **Title**: `Edit {filename}` +- **Body**: Diff/patch showing changes from `metadata.diff` +- **Special**: Shows diagnostics if available in metadata +- **Use case**: Shows what changes are being made to files + +### 3. **write** - File Writing + +- **Title**: `Write {filename}` +- **Body**: File content being written (first 10 lines) +- **Special**: Shows diagnostics if available in metadata +- **Use case**: Shows new file content being created + +### 4. **bash** - Shell Commands + +- **Title**: `Shell {description}` (or command if no description) +- **Body**: Console-style display with `$ command` and output + +``` +$ npm install vitest +added 50 packages... +``` + +- **Output from**: `metadata.output` +- **Use case**: Shows command execution and results + +### 5. **webfetch** - Web Fetching + +- **Title**: `Fetch {url}` +- **Body**: Fetched content (first 10 lines) +- **Use case**: Shows web content being retrieved + +### 6. **todowrite** - Task Planning + +- **Title**: Dynamic based on todo phase: + - All pending: "Creating plan" + - All completed: "Completing plan" + - Mixed: "Updating plan" +- **Body**: Formatted todo list: + - `- [x] Completed task` + - `- [ ] Pending task` + - `- [ ] ~~Cancelled task~~` + - `- [ ] In progress task` (highlighted) +- **Use case**: Shows the AI's task planning + +### 7. **task** - Delegated Tasks + +- **Title**: `Task[subagent_type] {description}` +- **Body**: List of delegated tool calls with icons: + +``` +⚡ bash: npm install +📖 read package.json +✏️ edit src/app.ts +``` + +- **Special**: In TUI, includes navigation hints for session tree +- **Use case**: Shows what the delegated agent is doing + +### 8. **todoread** - Plan Reading + +- **Special**: Hidden in TUI, returns empty string +- **Use case**: Internal tool, not displayed to user + +### 9. **glob** - File Pattern Matching + +- **Title**: `Glob {pattern}` +- **Use case**: Shows file search patterns + +### 10. **grep** - Content Search + +- **Title**: `Grep "{pattern}"` +- **Use case**: Shows what content is being searched + +### 11. **list** - Directory Listing + +- **Title**: `List` +- **Use case**: Shows directory operations + +### 12. **patch** - Patching Files + +- **Title**: `Patch` +- **Use case**: Shows patch operations + +### 13. **invalid** - Invalid Tool Calls + +- **Title**: Name of the actual tool attempted +- **Use case**: Shows validation errors + +### 14. **Default** - Unknown Tools + +- **Title**: Capitalized tool name +- **Body**: Output truncated to 10 lines +- **Use case**: Fallback for any new or custom tools + +## Status States + +### Pending + +- **Icon**: ⏸ (pause symbol) +- **Title**: Action text (e.g., "Writing command...", "Preparing edit...") +- **Border**: Accent color +- **Animation**: Shimmer effect on title +- **Expandable**: Shows "Waiting for permission..." message + +### Running + +- **Icon**: ⏳ (hourglass) +- **Title**: Same as completed state +- **Border**: Warning color (yellow/orange) +- **Animation**: Pulse on status icon + +### Completed + +- **Icon**: ✓ (checkmark) +- **Title**: Tool-specific title with arguments +- **Border**: Success color (green) +- **Body**: Tool-specific rendered content + +### Error + +- **Icon**: ✗ (X mark) +- **Title**: Same format but in error color +- **Border**: Error color (red) +- **Body**: Error message in highlighted box + +## Title Rendering Logic + +The title follows this pattern: + +1. **Pending state**: Show action text + + ``` + "Writing command..." + "Preparing edit..." + "Delegating..." + ``` + +2. **Completed/Running/Error**: Show specific info + + ``` + "Shell npm install" + "Edit src/app.ts" + "Read package.json" + "Task[general] Search for files" + ``` + +3. **Special cases**: + - `todowrite`: Shows plan phase + - `todoread`: Just "Plan" + - `bash`: Uses description if available, otherwise shows command + +## Metadata Usage + +Tool calls use `metadata` for rich content: + +- **read**: `metadata.preview` - file preview content +- **edit**: `metadata.diff` - patch/diff text +- **bash**: `metadata.output` - command output +- **todowrite**: `metadata.todos[]` - todo items with status +- **task**: `metadata.summary[]` - delegated tool calls +- **edit/write**: `metadata.diagnostics` - LSP diagnostics + +## Design Principles + +1. **Context-specific**: Each tool shows the most relevant information +2. **Progressive disclosure**: Collapsed by default, expand for details +3. **Visual hierarchy**: Icons, colors, and borders indicate status +4. **Truncation**: Long content is truncated (6-10 lines) to prevent overwhelming +5. **Consistency**: All tools follow same header/body/error structure + +## Component Structure + +```tsx +
+ + + {expanded && ( +
+ {/* Tool-specific body content */} + {error &&
{error}
} +
+ )} +
+``` + +## CSS Classes + +- `.tool-call` - Base container +- `.tool-call-status-{pending|running|completed|error}` - Status-specific styling +- `.tool-call-header` - Clickable header with expand/collapse +- `.tool-call-emoji` - Tool type icon +- `.tool-call-summary` - Tool title/description +- `.tool-call-details` - Expanded content area +- `.tool-call-content` - Code/output content (monospace) +- `.tool-call-todos` - Todo list container +- `.tool-call-task-summary` - Delegated task list +- `.tool-call-error-content` - Error message display + +## Future Enhancements + +1. **Syntax highlighting**: Use Shiki for code blocks in bash, read, write +2. **Diff rendering**: Better diff visualization for edit tool +3. **Copy buttons**: Quick copy for code/output +4. **File links**: Click filename to open in editor +5. **Diagnostics display**: Show LSP errors/warnings inline diff --git a/dev-docs/architecture.md b/dev-docs/architecture.md new file mode 100644 index 0000000..21f9465 --- /dev/null +++ b/dev-docs/architecture.md @@ -0,0 +1,312 @@ +# CodeNomad Architecture + +## Overview + +CodeNomad is a cross-platform desktop application built with Electron that provides a multi-instance, multi-session interface for interacting with OpenCode servers. Each instance manages its own OpenCode server process and can handle multiple concurrent sessions. + +## High-Level Architecture + +``` +┌─────────────────────────────────────────────────────────┐ +│ Electron Main Process │ +│ - Window management │ +│ - Process spawning (opencode serve) │ +│ - IPC bridge to renderer │ +│ - File system operations │ +└────────────────┬────────────────────────────────────────┘ + │ IPC +┌────────────────┴────────────────────────────────────────┐ +│ Electron Renderer Process │ +│ ┌──────────────────────────────────────────────────┐ │ +│ │ SolidJS Application │ │ +│ │ ┌────────────────────────────────────────────┐ │ │ +│ │ │ Instance Manager │ │ │ +│ │ │ - Spawns/kills OpenCode servers │ │ │ +│ │ │ - Manages SDK clients per instance │ │ │ +│ │ │ - Handles port allocation │ │ │ +│ │ └────────────────────────────────────────────┘ │ │ +│ │ ┌────────────────────────────────────────────┐ │ │ +│ │ │ State Management (SolidJS Stores) │ │ │ +│ │ │ - instances[] │ │ │ +│ │ │ - sessions[] per instance │ │ │ +│ │ │ - normalized message store per session │ │ │ +│ │ └────────────────────────────────────────────┘ │ │ +│ │ ┌────────────────────────────────────────────┐ │ │ +│ │ │ UI Components │ │ │ +│ │ │ - InstanceTabs │ │ │ +│ │ │ - SessionTabs │ │ │ +│ │ │ - MessageSection │ │ │ +│ │ │ - PromptInput │ │ │ +│ │ └────────────────────────────────────────────┘ │ │ +│ └──────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────┘ + │ HTTP/SSE +┌────────────────┴────────────────────────────────────────┐ +│ Multiple OpenCode Server Processes │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ Instance 1 │ │ Instance 2 │ │ Instance 3 │ │ +│ │ Port: 4096 │ │ Port: 4097 │ │ Port: 4098 │ │ +│ │ ~/project-a │ │ ~/project-a │ │ ~/api │ │ +│ └──────────────┘ └──────────────┘ └──────────────┘ │ +└─────────────────────────────────────────────────────────┘ +``` + +## Component Layers + +### 1. Main Process Layer (Electron) + +**Responsibilities:** + +- Create and manage application window +- Spawn OpenCode server processes as child processes +- Parse server stdout to extract port information +- Handle process lifecycle (start, stop, restart) +- Provide IPC handlers for renderer requests +- Manage native OS integrations (file dialogs, menus) + +**Key Modules:** + +- `main.ts` - Application entry point +- `process-manager.ts` - OpenCode server process spawning +- `ipc-handlers.ts` - IPC communication handlers +- `menu.ts` - Native application menu + +### 2. Renderer Process Layer (SolidJS) + +**Responsibilities:** + +- Render UI components +- Manage application state +- Handle user interactions +- Communicate with OpenCode servers via HTTP/SSE +- Real-time message streaming + +**Key Modules:** + +- `App.tsx` - Root component +- `stores/` - State management +- `components/` - UI components +- `contexts/` - SolidJS context providers +- `lib/` - Utilities and helpers + +### 3. Communication Layer + +**HTTP API Communication:** + +- SDK client per instance +- RESTful API calls for session/config/file operations +- Error handling and retries + +**SSE (Server-Sent Events):** + +- One EventSource per instance +- Real-time message updates +- Event type routing +- Reconnection logic + +**CLI Proxy Paths:** + +- The CLI server terminates all HTTP/SSE traffic and forwards it to the correct OpenCode instance. +- Each `WorkspaceDescriptor` exposes `proxyPath` (e.g., `/workspaces//instance`), which acts as the base URL for both REST and SSE calls. +- The renderer never touches the random per-instance port directly; it only talks to `window.location.origin + proxyPath` so a single CLI port can front every session. + +## Data Flow + +### Instance Creation Flow + +1. User selects folder via Electron file dialog +2. Main process receives folder path via IPC +3. Main process spawns `opencode serve --port 0` +4. Main process parses stdout for port number +5. Main process sends port + PID back to renderer +6. Renderer creates SDK client for that port +7. Renderer fetches initial session list +8. Renderer displays session picker + +### Message Streaming Flow + +1. User submits prompt in active session +2. Renderer POSTs to `/session/:id/message` +3. SSE connection receives `MessageUpdated` events +4. Events are routed to correct instance → session +5. Message state updates trigger UI re-render +6. Messages display with auto-scroll + +### Child Session Creation Flow + +1. OpenCode server creates child session +2. SSE emits `SessionUpdated` event with `parentId` +3. Renderer adds session to instance's session list +4. New session tab appears automatically +5. Optional: Auto-switch to new tab + +## State Management + +### Instance State + +``` +instances: Map + activeSessionId: string | null + logs: string[] +}> +``` + +### Session State + +``` +Session: { + id: string + title: string + parentId: string | null + messages: Message[] + agent: string + model: { providerId: string, modelId: string } + status: 'idle' | 'streaming' | 'error' +} +``` + +### Message State + +``` +Message: { + id: string + sessionId: string + type: 'user' | 'assistant' + parts: Part[] + timestamp: number + status: 'sending' | 'sent' | 'streaming' | 'complete' | 'error' +} +``` + +## Tab Hierarchy + +### Level 1: Instance Tabs + +Each tab represents one OpenCode server instance: + +- Label: Folder name (with counter if duplicate) +- Icon: Folder icon +- Close button: Stops server and closes tab +- "+" button: Opens folder picker for new instance + +### Level 2: Session Tabs + +Each instance has multiple session tabs: + +- Main session tab (always present) +- Child session tabs (auto-created) +- Logs tab (shows server output) +- "+" button: Creates new session + +### Tab Behavior + +**Instance Tab Switching:** + +- Preserves session tabs +- Switches active SDK client +- Updates SSE event routing + +**Session Tab Switching:** + +- Loads messages for that session +- Updates agent/model controls +- Preserves scroll position + +## Technology Stack + +### Core + +- **Electron** - Desktop wrapper +- **SolidJS** - Reactive UI framework +- **TypeScript** - Type safety +- **Vite** - Build tool + +### UI + +- **TailwindCSS** - Styling +- **Kobalte** - Accessible UI primitives +- **Shiki** - Code syntax highlighting +- **Marked** - Markdown parsing + +### Communication + +- **OpenCode SDK** - API client +- **EventSource** - SSE streaming +- **Node Child Process** - Process spawning + +## Error Handling + +### Process Errors + +- Server fails to start → Show error in instance tab +- Server crashes → Attempt auto-restart once +- Port already in use → Find next available port + +### Network Errors + +- API call fails → Show inline error, allow retry +- SSE disconnects → Auto-reconnect with backoff +- Timeout → Show timeout error, allow manual retry + +### User Errors + +- Invalid folder selection → Show error dialog +- Permission denied → Show actionable error message +- Out of memory → Graceful degradation message + +## Performance Considerations + +**Note: Performance optimization is NOT a focus for MVP. These are future considerations.** + +### Message Rendering (Post-MVP) + +- Start with simple list rendering - no virtual scrolling +- No message limits initially +- Only optimize if users report issues +- Virtual scrolling can be added in Phase 8 if needed + +### State Updates + +- SolidJS fine-grained reactivity handles most cases +- No special optimizations needed for MVP +- Batching/debouncing can be added later if needed + +### Memory Management (Post-MVP) + +- No memory management in MVP +- Let browser/OS handle it +- Add limits only if problems arise in testing + +## Security Considerations + +- No remote code execution +- Server spawned with user permissions +- No eval() or dangerous innerHTML +- Sanitize markdown rendering +- Validate all IPC messages +- HTTPS only for external requests + +## Extensibility Points + +### Plugin System (Future) + +- Custom slash commands +- Custom message renderers +- Theme extensions +- Keybinding customization + +### Configuration (Future) + +- Per-instance settings +- Global preferences +- Workspace-specific configs +- Import/export settings diff --git a/dev-docs/build-roadmap.md b/dev-docs/build-roadmap.md new file mode 100644 index 0000000..1fd48cb --- /dev/null +++ b/dev-docs/build-roadmap.md @@ -0,0 +1,391 @@ +# CodeNomad Build Roadmap + +## Overview + +This document outlines the phased approach to building the CodeNomad desktop application. Each phase builds incrementally on the previous, with clear deliverables and milestones. + +**Status:** MVP (Phases 1-3) is complete. Focus now shifts to post-MVP phases starting with multi-instance support and advanced input refinements. + +## MVP Scope (Phases 1-3) + +The minimum viable product includes: + +- Single instance management +- Session selection and creation +- Message display (streaming) +- Basic prompt input (text only) +- Agent/model selection +- Process lifecycle management + +**Target: 3-4 weeks for MVP** + +--- + +## Phase 1: Foundation (Week 1) + +**Goal:** Running Electron app that can spawn OpenCode servers + +### Tasks + +1. ✅ **001-project-setup** - Electron + SolidJS + Vite boilerplate +2. ✅ **002-empty-state-ui** - Empty state UI with folder selection +3. ✅ **003-process-manager** - Spawn and manage OpenCode server processes +4. ✅ **004-sdk-integration** - Connect to server via SDK +5. ✅ **005-session-picker-modal** - Select/create session modal + +### Deliverables + +- App launches successfully +- Can select folder +- Server spawns automatically +- Session picker appears +- Can create/select session + +### Success Criteria + +- User can launch app → select folder → see session picker +- Server process runs in background +- Sessions fetch from API successfully + +--- + +## Phase 2: Core Chat Interface (Week 2) + +**Goal:** Display messages and send basic prompts + +### Tasks + +6. **006-instance-session-tabs** - Two-level tab navigation +7. **007-message-display** - Render user and assistant messages +8. **008-sse-integration** - Real-time message streaming +9. **009-prompt-input-basic** - Text input with send functionality +10. **010-tool-call-rendering** - Display tool executions inline + +### Deliverables + +- Tab navigation works +- Messages display correctly +- Real-time updates via SSE +- Can send text messages +- Tool calls show status + +### Success Criteria + +- User can type message → see response stream in real-time +- Tool executions visible and expandable +- Multiple sessions can be open simultaneously + +--- + +## Phase 3: Essential Features (Week 3) + +**Goal:** Feature parity with basic TUI functionality + +### Tasks + +11. **011-agent-model-selectors** - Dropdown for agent/model switching +12. **012-markdown-rendering** - Proper markdown with code highlighting +13. **013-logs-tab** - View server logs +14. **014-error-handling** - Comprehensive error states and recovery +15. **015-keyboard-shortcuts** - Essential keyboard navigation + +### Deliverables + +- Can switch agents and models +- Markdown renders beautifully +- Code blocks have syntax highlighting +- Server logs accessible +- Errors handled gracefully +- Cmd/Ctrl+N, K, L shortcuts work + +### Success Criteria + +- User experience matches TUI quality +- All error cases handled +- Keyboard-first navigation option available + +--- + +## Phase 4: Multi-Instance Support (Week 4) + +**Goal:** Work on multiple projects simultaneously + +### Tasks + +16. **016-instance-tabs** - Instance-level tab management +17. **017-instance-state-persistence** - Remember instances across restarts +18. **018-child-session-handling** - Auto-create tabs for child sessions +19. **019-instance-lifecycle** - Stop, restart, reconnect instances +20. **020-multiple-sdk-clients** - One SDK client per instance + +### Deliverables + +- Multiple instance tabs +- Persists across app restarts +- Child sessions appear as new tabs +- Can stop individual instances +- All instances work independently + +### Success Criteria + +- User can work on 3+ projects simultaneously +- App remembers state on restart +- No interference between instances + +--- + +## Phase 5: Advanced Input (Week 5) + +**Goal:** Full input capabilities matching TUI + +### Tasks + +21. **021-slash-commands** - Command palette with autocomplete +22. **022-file-attachments** - @ mention file picker +23. **023-drag-drop-files** - Drag files onto input +24. **024-attachment-chips** - Display and manage attachments +25. **025-input-history** - Up/down arrow message history + +### Deliverables + +- `/command` autocomplete works +- `@file` picker searches files +- Drag & drop attaches files +- Attachment chips removable +- Previous messages accessible + +### Success Criteria + +- Input feature parity with TUI +- File context easy to add +- Command discovery intuitive + +--- + +## Phase 6: Polish & UX (Week 6) + +**Goal:** Production-ready user experience + +### Tasks + +26. **026-message-actions** - Copy, edit, regenerate messages +27. **027-search-in-session** - Find text in conversation +28. **028-session-management** - Rename, share, export sessions +29. **029-settings-ui** - Preferences and configuration +30. **030-native-menus** - Platform-native menu bar + +### Deliverables + +- Message context menus +- Search within conversation +- Session CRUD operations +- Settings dialog +- Native File/Edit/View menus + +### Success Criteria + +- Feels polished and professional +- All common actions accessible +- Settings discoverable + +--- + +## Phase 7: System Integration (Week 7) + +**Goal:** Native desktop app features + +### Tasks + +31. **031-system-tray** - Background running with tray icon +32. **032-notifications** - Desktop notifications for events +33. **033-auto-updater** - In-app update mechanism +34. **034-crash-reporting** - Error reporting and recovery +35. **035-performance-profiling** - Optimize rendering and memory + +### Deliverables + +- Runs in background +- Notifications for session activity +- Auto-updates on launch +- Crash logs captured +- Smooth performance with large sessions + +### Success Criteria + +- App feels native to platform +- Updates seamlessly +- Crashes don't lose data + +--- + +## Phase 8: Advanced Features (Week 8+) + +**Goal:** Beyond MVP, power user features + +### Tasks + +36. **036-virtual-scrolling** - Handle 1000+ message sessions +37. **037-message-search-advanced** - Full-text search across sessions +38. **038-workspace-management** - Save/load workspace configurations +39. **039-theme-customization** - Custom themes and UI tweaks +40. **040-plugin-system** - Extension API for custom tools + +### Deliverables + +- Virtual scrolling for performance +- Cross-session search +- Workspace persistence +- Theme editor +- Plugin loader + +### Success Criteria + +- Handles massive sessions (5000+ messages) +- Can search entire project history +- Fully customizable + +--- + +## Parallel Tracks + +Some tasks can be worked on independently: + +### Design Track + +- Visual design refinements +- Icon creation +- Brand assets +- Marketing materials + +### Documentation Track + +- User guide +- Keyboard shortcuts reference +- Troubleshooting docs +- Video tutorials + +### Infrastructure Track + +- CI/CD pipeline +- Automated testing +- Release automation +- Analytics integration + +--- + +## Release Strategy + +### Alpha (After Phase 3) + +- Internal testing only +- Frequent bugs expected +- Rapid iteration + +### Beta (After Phase 6) + +- Public beta program +- Feature complete +- Bug fixes and polish + +### v1.0 (After Phase 7) + +- Public release +- Stable and reliable +- Production-ready + +### v1.x (Phase 8+) + +- Regular feature updates +- Community-driven priorities +- Plugin ecosystem + +--- + +## Success Metrics + +### MVP Success + +- 10 internal users daily +- Can complete full coding session +- <5 critical bugs + +### Beta Success + +- 100+ external users +- NPS >50 +- <10 bugs per week + +### v1.0 Success + +- 1000+ users +- <1% crash rate +- Feature requests > bug reports + +--- + +## Risk Mitigation + +### Technical Risks + +- **Process management complexity** + - Mitigation: Extensive testing, graceful degradation +- **SSE connection stability** + - Mitigation: Robust reconnection logic, offline mode +- **Performance with large sessions** + - Mitigation: NOT a concern for MVP - defer to Phase 8 + - Accept slower performance initially, optimize later based on user feedback + +### Product Risks + +- **Feature creep** + - Mitigation: Strict MVP scope, user feedback prioritization +- **Over-optimization too early** + - Mitigation: Focus on functionality first, optimize in Phase 8 + - Avoid premature performance optimization +- **Platform inconsistencies** + - Mitigation: Test on all platforms regularly + +--- + +## Dependencies + +### External + +- OpenCode CLI availability +- OpenCode SDK stability +- Electron framework updates + +### Internal + +- Design assets +- Documentation +- Testing resources + +--- + +## Milestone Checklist + +### Pre-Alpha + +- [ ] All Phase 1 tasks complete +- [ ] Can create instance and session +- [ ] Internal demo successful + +### Alpha + +- [ ] All Phase 2-3 tasks complete +- [ ] MVP feature complete +- [ ] 5+ internal users testing + +### Beta + +- [ ] All Phase 4-6 tasks complete +- [ ] Multi-instance stable +- [ ] 50+ external testers + +### v1.0 + +- [ ] All Phase 7 tasks complete +- [ ] Documentation complete +- [ ] <5 known bugs +- [ ] Ready for public release diff --git a/dev-docs/solidjs-llms.txt b/dev-docs/solidjs-llms.txt new file mode 100644 index 0000000..0158a84 --- /dev/null +++ b/dev-docs/solidjs-llms.txt @@ -0,0 +1,82 @@ +# SolidJS Documentation + +> Solid is a modern JavaScript framework for building user interfaces with fine-grained reactivity. It compiles JSX to real DOM elements and updates only what changes, delivering exceptional performance without a virtual DOM. Solid provides reactive primitives like signals, effects, and stores for predictable state management. + +SolidJS is a declarative JavaScript framework that prioritizes performance and developer experience. Unlike frameworks that re-run components on every update, Solid components run once during initialization and set up a reactive system that precisely updates the DOM when dependencies change. + +Key principles: +- Fine-grained reactivity: Updates only the specific DOM nodes that depend on changed data +- Compile-time optimization: JSX transforms into efficient DOM operations +- Unidirectional data flow: Props are read-only, promoting predictable state management +- Component lifecycle: Components run once, with reactive primitives handling updates + +**Use your web fetch tool on any of the following links to understand the relevant concept**. + +## Quick Start + +- [Overview](https://docs.solidjs.com/): Framework introduction and key advantages +- [Quick Start](https://docs.solidjs.com/quick-start): Installation and project setup with create-solid +- [Interactive Tutorial](https://www.solidjs.com/tutorial/introduction_basics): Learn Solid basics through guided examples +- [Playground](https://playground.solidjs.com/): Experiment with Solid directly in your browser + +## Core Concepts + +- [Intro to Reactivity](https://docs.solidjs.com/concepts/intro-to-reactivity): Signals, subscribers, and reactive principles +- [Understanding JSX](https://docs.solidjs.com/concepts/understanding-jsx): How Solid uses JSX and key differences from HTML +- [Components Basics](https://docs.solidjs.com/concepts/components/basics): Component trees, lifecycles, and composition patterns +- [Signals](https://docs.solidjs.com/concepts/signals): Core reactive primitive for state management with getters/setters +- [Effects](https://docs.solidjs.com/concepts/effects): Side effects, dependency tracking, and lifecycle functions +- [Stores](https://docs.solidjs.com/concepts/stores): Complex state management with proxy-based reactivity +- [Context](https://docs.solidjs.com/concepts/context): Cross-component state sharing without prop drilling + +## Component APIs + +- [Props](https://docs.solidjs.com/concepts/components/props): Passing data and handlers to child components +- [Event Handlers](https://docs.solidjs.com/concepts/components/event-handlers): Managing user interactions +- [Class and Style](https://docs.solidjs.com/concepts/components/class-style): Dynamic styling approaches +- [Refs](https://docs.solidjs.com/concepts/refs): Accessing DOM elements directly + +## Control Flow + +- [Conditional Rendering](https://docs.solidjs.com/concepts/control-flow/conditional-rendering): Show, Switch, and Match components +- [List Rendering](https://docs.solidjs.com/concepts/control-flow/list-rendering): For, Index, and keyed iteration +- [Dynamic](https://docs.solidjs.com/concepts/control-flow/dynamic): Dynamic component switching +- [Portal](https://docs.solidjs.com/concepts/control-flow/portal): Rendering outside component hierarchy +- [Error Boundary](https://docs.solidjs.com/concepts/control-flow/error-boundary): Graceful error handling + +## Derived Values + +- [Derived Signals](https://docs.solidjs.com/concepts/derived-values/derived-signals): Computed values from signals +- [Memos](https://docs.solidjs.com/concepts/derived-values/memos): Cached computed values for performance + +## State Management + +- [Basic State Management](https://docs.solidjs.com/guides/state-management): One-way data flow and lifting state +- [Complex State Management](https://docs.solidjs.com/guides/complex-state-management): Stores for scalable applications +- [Fetching Data](https://docs.solidjs.com/guides/fetching-data): Async data with createResource + +## Routing + +- [Routing & Navigation](https://docs.solidjs.com/guides/routing-and-navigation): @solidjs/router setup and usage +- [Dynamic Routes](https://docs.solidjs.com/guides/routing-and-navigation#dynamic-routes): Route parameters and validation +- [Nested Routes](https://docs.solidjs.com/guides/routing-and-navigation#nested-routes): Hierarchical route structures +- [Preload Functions](https://docs.solidjs.com/guides/routing-and-navigation#preload-functions): Parallel data fetching + +## Advanced Topics + +- [Fine-Grained Reactivity](https://docs.solidjs.com/advanced-concepts/fine-grained-reactivity): Deep dive into reactive system +- [TypeScript](https://docs.solidjs.com/configuration/typescript): Type safety and configuration + +## Ecosystem + +- [Solid Router](https://docs.solidjs.com/solid-router/): File-system routing and data APIs +- [SolidStart](https://docs.solidjs.com/solid-start/): Full-stack meta-framework +- [Solid Meta](https://docs.solidjs.com/solid-meta/): Document head management +- [Templates](https://github.com/solidjs/templates): Starter templates for different setups + +## Optional + +- [Ecosystem Libraries](https://www.solidjs.com/ecosystem): Community packages and tools +- [API Reference](https://docs.solidjs.com/reference/): Complete API documentation +- [Testing](https://docs.solidjs.com/guides/testing): Testing strategies and utilities +- [Deployment](https://docs.solidjs.com/guides/deploying-your-app): Build and deployment options diff --git a/dev-docs/technical-implementation.md b/dev-docs/technical-implementation.md new file mode 100644 index 0000000..5d7e6d6 --- /dev/null +++ b/dev-docs/technical-implementation.md @@ -0,0 +1,642 @@ +# Technical Implementation Details + +## Technology Stack + +### Core Technologies + +- **Electron** v28+ - Desktop application wrapper +- **SolidJS** v1.8+ - Reactive UI framework +- **TypeScript** v5.3+ - Type-safe development +- **Vite** v5+ - Fast build tool and dev server + +### UI & Styling + +- **TailwindCSS** v4+ - Utility-first styling +- **Kobalte** - Accessible UI primitives for SolidJS +- **Shiki** - Syntax highlighting for code blocks +- **Marked** - Markdown parsing +- **Lucide** - Icon library + +### Communication + +- **OpenCode SDK** (@opencode-ai/sdk) - API client +- **EventSource API** - Server-sent events +- **Node Child Process** - Process management + +### Development Tools + +- **electron-vite** - Electron + Vite integration +- **electron-builder** - Application packaging +- **ESLint** - Code linting +- **Prettier** - Code formatting + +## Project Structure + +``` +packages/opencode-client/ +├── electron/ +│ ├── main/ +│ │ ├── main.ts # Electron main entry +│ │ ├── window.ts # Window management +│ │ ├── process-manager.ts # OpenCode server spawning +│ │ ├── ipc.ts # IPC handlers +│ │ └── menu.ts # Application menu +│ ├── preload/ +│ │ └── index.ts # Preload script (IPC bridge) +│ └── resources/ +│ └── icon.png # Application icon +├── src/ +│ ├── components/ +│ │ ├── instance-tabs.tsx # Level 1 tabs +│ │ ├── session-tabs.tsx # Level 2 tabs +│ │ ├── message-stream-v2.tsx # Messages display (normalized store) +│ │ ├── message-item.tsx # Single message +│ │ ├── tool-call.tsx # Tool execution display +│ │ ├── prompt-input.tsx # Input with attachments +│ │ ├── agent-selector.tsx # Agent dropdown +│ │ ├── model-selector.tsx # Model dropdown +│ │ ├── session-picker.tsx # Startup modal +│ │ ├── logs-view.tsx # Server logs +│ │ └── empty-state.tsx # No instances view +│ ├── stores/ +│ │ ├── instances.ts # Instance state +│ │ ├── sessions.ts # Session state per instance +│ │ └── ui.ts # UI state (active tabs, etc) +│ ├── lib/ +│ │ ├── sdk-manager.ts # SDK client management +│ │ ├── sse-manager.ts # SSE connection handling +│ │ ├── port-finder.ts # Find available ports +│ │ └── markdown.ts # Markdown rendering utils +│ ├── hooks/ +│ │ ├── use-instance.ts # Instance operations +│ │ ├── use-session.ts # Session operations +│ │ └── use-messages.ts # Message operations +│ ├── types/ +│ │ ├── instance.ts # Instance types +│ │ ├── session.ts # Session types +│ │ └── message.ts # Message types +│ ├── App.tsx # Root component +│ ├── main.tsx # Renderer entry +│ └── index.css # Global styles +├── docs/ # Documentation +├── tasks/ # Task tracking +├── package.json +├── tsconfig.json +├── electron.vite.config.ts +├── tailwind.config.js +└── README.md +``` + +## State Management + +### Instance Store + +```typescript +interface InstanceState { + instances: Map + activeInstanceId: string | null + + // Actions + createInstance(folder: string): Promise + removeInstance(id: string): Promise + setActiveInstance(id: string): void +} + +interface Instance { + id: string // UUID + folder: string // Absolute path + port: number // Server port + pid: number // Process ID + status: InstanceStatus + client: OpenCodeClient // SDK client + eventSource: EventSource | null // SSE connection + sessions: Map + activeSessionId: string | null + logs: LogEntry[] +} + +type InstanceStatus = + | "starting" // Server spawning + | "ready" // Server connected + | "error" // Failed to start + | "stopped" // Server killed + +interface LogEntry { + timestamp: number + level: "info" | "error" | "warn" + message: string +} +``` + +### Session Store + +```typescript +interface SessionState { + // Per instance + getSessions(instanceId: string): Session[] + getActiveSession(instanceId: string): Session | null + + // Actions + createSession(instanceId: string, agent: string): Promise + deleteSession(instanceId: string, sessionId: string): Promise + setActiveSession(instanceId: string, sessionId: string): void + updateSession(instanceId: string, sessionId: string, updates: Partial): void +} + +interface Session { + id: string + instanceId: string + title: string + parentId: string | null + agent: string + model: { + providerId: string + modelId: string + } + version: string + time: { created: number; updated: number } + revert?: { + messageID?: string + partID?: string + snapshot?: string + diff?: string + } +} + +// Message content lives in the normalized message-v2 store +// keyed by instanceId/sessionId/messageId + +type SessionStatus = + | "idle" // No activity + | "streaming" // Assistant responding + | "error" // Error occurred + +``` + +### UI Store + +```typescript +interface UIState { + // Tab state + instanceTabOrder: string[] + sessionTabOrder: Map // instanceId -> sessionIds + + // Modal state + showSessionPicker: string | null // instanceId or null + showSettings: boolean + + // Actions + reorderInstanceTabs(newOrder: string[]): void + reorderSessionTabs(instanceId: string, newOrder: string[]): void + openSessionPicker(instanceId: string): void + closeSessionPicker(): void +} +``` + +## Process Management + +### Server Spawning + +**Strategy:** Spawn with port 0 (random), parse stdout for actual port + +```typescript +interface ProcessManager { + spawn(folder: string): Promise + kill(pid: number): Promise + restart(pid: number, folder: string): Promise +} + +interface ProcessInfo { + pid: number + port: number + stdout: Readable + stderr: Readable +} + +// Implementation approach: +// 1. Check if opencode binary exists +// 2. Spawn: spawn('opencode', ['serve', '--port', '0'], { cwd: folder }) +// 3. Listen to stdout +// 4. Parse line matching: "Server listening on port 4096" +// 5. Resolve promise with port +// 6. Timeout after 10 seconds +``` + +### Port Parsing + +```typescript +// Expected output from opencode serve: +// > Starting OpenCode server... +// > Server listening on port 4096 +// > API available at http://localhost:4096 + +function parsePort(output: string): number | null { + const match = output.match(/port (\d+)/) + return match ? parseInt(match[1], 10) : null +} +``` + +### Error Handling + +**Server fails to start:** + +- Parse stderr for error message +- Display in instance tab with retry button +- Common errors: Port in use, permission denied, binary not found + +**Server crashes after start:** + +- Detect via process 'exit' event +- Attempt auto-restart once +- If restart fails, show error state +- Preserve session data for manual restart + +## Communication Layer + +### SDK Client Management + +```typescript +interface SDKManager { + createClient(port: number): OpenCodeClient + destroyClient(port: number): void + getClient(port: number): OpenCodeClient | null +} + +// One client per instance +// Client lifecycle tied to instance lifecycle +``` + +### SSE Event Handling + +```typescript +interface SSEManager { + connect(instanceId: string, port: number): void + disconnect(instanceId: string): void + + // Event routing + onMessageUpdate(handler: (instanceId: string, event: MessageUpdateEvent) => void): void + onSessionUpdate(handler: (instanceId: string, event: SessionUpdateEvent) => void): void + onError(handler: (instanceId: string, error: Error) => void): void +} + +// Event flow: +// 1. EventSource connects to /event endpoint +// 2. Events arrive as JSON +// 3. Route to correct instance store +// 4. Update reactive state +// 5. UI auto-updates via signals +``` + +### Reconnection Logic + +```typescript +// SSE disconnects: +// - Network issue +// - Server restart +// - Tab sleep (browser optimization) + +class SSEConnection { + private reconnectAttempts = 0 + private maxReconnectAttempts = 5 + private reconnectDelay = 1000 // Start with 1s + + reconnect() { + if (this.reconnectAttempts >= this.maxReconnectAttempts) { + this.emitError(new Error("Max reconnection attempts reached")) + return + } + + setTimeout(() => { + this.connect() + this.reconnectAttempts++ + this.reconnectDelay *= 2 // Exponential backoff + }, this.reconnectDelay) + } +} +``` + +## Message Rendering + +### Markdown Processing + +```typescript +// Use Marked + Shiki for syntax highlighting +import { marked } from "marked" +import { markedHighlight } from "marked-highlight" +import { getHighlighter } from "shiki" + +const highlighter = await getHighlighter({ + themes: ["github-dark", "github-light"], + langs: ["typescript", "javascript", "python", "bash", "json"], +}) + +marked.use( + markedHighlight({ + highlight(code, lang) { + return highlighter.codeToHtml(code, { + lang, + theme: isDark ? "github-dark" : "github-light", + }) + }, + }), +) +``` + +### Tool Call Rendering + +```typescript +interface ToolCallComponent { + tool: string // "bash", "edit", "read" + input: any // Tool-specific input + output?: any // Tool-specific output + status: "pending" | "running" | "success" | "error" + expanded: boolean // Collapse state +} + +// Render logic: +// - Default: Collapsed, show summary +// - Click: Toggle expanded state +// - Running: Show spinner +// - Complete: Show checkmark +// - Error: Show error icon + message +``` + +### Streaming Updates + +```typescript +// Messages stream in via SSE +// Update strategy: Replace existing message parts + +function handleMessagePartUpdate(event: MessagePartEvent) { + const session = getSession(event.sessionId) + const message = session.messages.find((m) => m.id === event.messageId) + + if (!message) { + // New message + session.messages.push(createMessage(event)) + } else { + // Update existing + const partIndex = message.parts.findIndex((p) => p.id === event.partId) + if (partIndex === -1) { + message.parts.push(event.part) + } else { + message.parts[partIndex] = event.part + } + } + + // SolidJS reactivity triggers re-render +} +``` + +## Performance Considerations + +**MVP Approach: Don't optimize prematurely** + +### Message Rendering (MVP) + +**Simple approach - no optimization:** + +```typescript +// Render all messages - no virtual scrolling, no limits + + {(message) => } + + +// SolidJS will handle reactivity efficiently +// Only optimize if users report issues +``` + +### State Update Batching + +**Not needed for MVP:** + +- SolidJS reactivity is efficient enough +- SSE updates will just trigger normal re-renders +- Add batching only if performance issues arise + +### Memory Management + +**Not needed for MVP:** + +- No message limits +- No pruning +- No lazy loading +- Let users create as many messages as they want +- Optimize later if problems occur + +**When to add optimizations (post-MVP):** + +- Users report slowness with large sessions +- Measurable performance degradation +- Memory usage becomes problematic +- See Phase 8 tasks for virtual scrolling and optimization + +## IPC Communication + +### Main Process → Renderer + +```typescript +// Events sent from main to renderer +type MainToRenderer = { + "instance:started": { id: string; port: number; pid: number } + "instance:error": { id: string; error: string } + "instance:stopped": { id: string } + "instance:log": { id: string; entry: LogEntry } +} +``` + +### Renderer → Main Process + +```typescript +// Commands sent from renderer to main +type RendererToMain = { + "folder:select": () => Promise + "instance:create": (folder: string) => Promise<{ port: number; pid: number }> + "instance:stop": (pid: number) => Promise + "app:quit": () => void +} +``` + +### Preload Script (Bridge) + +```typescript +// Expose safe IPC methods to renderer +contextBridge.exposeInMainWorld("electronAPI", { + selectFolder: () => ipcRenderer.invoke("folder:select"), + createInstance: (folder: string) => ipcRenderer.invoke("instance:create", folder), + stopInstance: (pid: number) => ipcRenderer.invoke("instance:stop", pid), + onInstanceStarted: (callback) => ipcRenderer.on("instance:started", callback), + onInstanceError: (callback) => ipcRenderer.on("instance:error", callback), +}) +``` + +## Error Handling Strategy + +### Network Errors + +```typescript +// HTTP request fails +try { + const response = await client.session.list() +} catch (error) { + if (error.code === "ECONNREFUSED") { + // Server not responding + showError("Cannot connect to server. Is it running?") + } else if (error.code === "ETIMEDOUT") { + // Request timeout + showError("Request timed out. Retry?", { retry: true }) + } else { + // Unknown error + showError(error.message) + } +} +``` + +### SSE Errors + +```typescript +eventSource.onerror = (error) => { + // Connection lost + if (eventSource.readyState === EventSource.CLOSED) { + // Attempt reconnect + reconnectSSE() + } +} +``` + +### User Input Errors + +```typescript +// Validate before sending +function validatePrompt(text: string): string | null { + if (!text.trim()) { + return "Message cannot be empty" + } + if (text.length > 10000) { + return "Message too long (max 10000 characters)" + } + return null +} +``` + +## Security Measures + +### IPC Security + +- Use `contextIsolation: true` +- Whitelist allowed IPC channels +- Validate all data from renderer +- No `nodeIntegration` in renderer + +### Process Security + +- Spawn OpenCode with user permissions only +- No shell execution of user input +- Sanitize file paths + +### Content Security + +- Sanitize markdown before rendering +- Use DOMPurify for HTML sanitization +- No `dangerouslySetInnerHTML` without sanitization +- CSP headers in renderer + +## Testing Strategy (Future) + +### Unit Tests + +- State management logic +- Utility functions +- Message parsing + +### Integration Tests + +- Process spawning +- SDK client operations +- SSE event handling + +### E2E Tests + +- Complete user flows +- Multi-instance scenarios +- Error recovery + +## Build & Packaging + +### Development + +```bash +npm run dev # Start Electron + Vite dev server +npm run dev:main # Main process only +npm run dev:renderer # Renderer only +``` + +### Production + +```bash +npm run build # Build all +npm run build:main # Build main process +npm run build:renderer # Build renderer +npm run package # Create distributable +``` + +### Distribution + +- macOS: DMG + auto-update +- Windows: NSIS installer + auto-update +- Linux: AppImage + deb/rpm + +## Configuration Files + +### electron.vite.config.ts + +```typescript +import { defineConfig } from "electron-vite" +import solid from "vite-plugin-solid" + +export default defineConfig({ + main: { + build: { + rollupOptions: { + external: ["electron"], + }, + }, + }, + preload: { + build: { + rollupOptions: { + external: ["electron"], + }, + }, + }, + renderer: { + plugins: [solid()], + resolve: { + alias: { + "@": "/src", + }, + }, + }, +}) +``` + +### tsconfig.json + +```json +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "lib": ["ES2020", "DOM"], + "jsx": "preserve", + "jsxImportSource": "solid-js", + "moduleResolution": "bundler", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "paths": { + "@/*": ["./src/*"] + } + } +} +``` diff --git a/dev-docs/user-interface.md b/dev-docs/user-interface.md new file mode 100644 index 0000000..3ea3f62 --- /dev/null +++ b/dev-docs/user-interface.md @@ -0,0 +1,493 @@ +# User Interface Specification + +## Overview + +The CodeNomad interface consists of a two-level tabbed layout with instance tabs at the top and session tabs below. Each session displays a message stream and prompt input. + +## Layout Structure + +``` +┌──────────────────────────────────────────────────────────────┐ +│ File Edit View Window Help ● ○ ◐ │ ← Native menu bar +├──────────────────────────────────────────────────────────────┤ +│ [~/project-a] [~/project-a (2)] [~/api-service] [+] │ ← Instance tabs (Level 1) +├──────────────────────────────────────────────────────────────┤ +│ [Main] [Fix login] [Write tests] [Logs] [+] │ ← Session tabs (Level 2) +├──────────────────────────────────────────────────────────────┤ +│ │ +│ ┌────────────────────────────────────────────────────────┐ │ +│ │ Messages Area │ │ +│ │ │ │ +│ │ User: How do I set up testing? │ │ +│ │ │ │ +│ │ Assistant: To set up testing, you'll need to... │ │ +│ │ → bash: npm install vitest ✓ │ │ +│ │ Output: added 50 packages │ │ +│ │ │ │ +│ └────────────────────────────────────────────────────────┘ │ +│ │ +├──────────────────────────────────────────────────────────────┤ +│ Agent: Build ▼ Model: Claude 3.5 Sonnet ▼ │ ← Controls +├──────────────────────────────────────────────────────────────┤ +│ [@file.ts] [@api.ts] [×] │ ← Attachments +│ ┌────────────────────────────────────────────────────────┐ │ +│ │ Type your message or /command... │ │ ← Prompt input +│ │ │ │ +│ └────────────────────────────────────────────────────────┘ │ +│ [▶] │ ← Send button +└──────────────────────────────────────────────────────────────┘ +``` + +## Components Specification + +### 1. Instance Tabs (Level 1) + +**Visual Design:** + +- Horizontal tabs at top of window +- Each tab shows folder name +- Icon: Folder icon (🗂️) +- Close button (×) on hover +- Active tab: Highlighted with accent color +- Inactive tabs: Muted background + +**Tab Label Format:** + +- Single instance: `~/project-name` +- Multiple instances of same folder: `~/project-name (2)`, `~/project-name (3)` +- Max width: 200px with ellipsis for long paths +- Tooltip shows full path on hover + +**Actions:** + +- Click: Switch to that instance +- Close (×): Stop server and close instance (with confirmation) +- Drag: Reorder tabs (future) + +**New Instance Button (+):** + +- Always visible at right end +- Click: Opens folder picker dialog +- Keyboard: Cmd/Ctrl+N + +**States:** + +- Starting: Loading spinner + "Starting..." +- Ready: Normal appearance +- Error: Red indicator + error icon +- Stopped: Grayed out (should not be visible, tab closes) + +### 2. Session Tabs (Level 2) + +**Visual Design:** + +- Horizontal tabs below instance tabs +- Smaller than instance tabs +- Each tab shows session title or "Untitled" +- Active tab: Underline or bold +- Parent-child relationship: No visual distinction (all siblings) + +**Tab Types:** + +**Session Tab:** + +- Label: Session title (editable on double-click) +- Icon: Chat bubble (💬) or none +- Close button (×) on hover +- Max width: 150px with ellipsis + +**Logs Tab:** + +- Label: "Logs" +- Icon: Terminal (⚡) +- Always present per instance +- Non-closable +- Shows server stdout/stderr + +**Actions:** + +- Click: Switch to that session +- Double-click label: Rename session +- Close (×): Delete session (with confirmation if has messages) +- Right-click: Context menu (Share, Export, Delete) + +**New Session Button (+):** + +- Click: Creates new session with default agent +- Keyboard: Cmd/Ctrl+T + +### 3. Messages Area + +**Container:** + +- Scrollable viewport +- Auto-scroll to bottom when new messages arrive +- Manual scroll up: Disable auto-scroll +- "Scroll to bottom" button appears when scrolled up + +**Message Layout:** + +**User Message:** + +``` +┌──────────────────────────────────────────┐ +│ You 10:32 AM │ +│ How do I set up testing? │ +│ │ +│ [@src/app.ts] [@package.json] │ ← Attachments if any +└──────────────────────────────────────────┘ +``` + +**Assistant Message:** + +```` +┌──────────────────────────────────────────┐ +│ Assistant • Build 10:32 AM │ +│ To set up testing, you'll need to │ +│ install Vitest and configure it. │ +│ │ +│ ▶ bash: npm install vitest ✓ │ ← Tool call (collapsed) +│ │ +│ ▶ edit src/vitest.config.ts ✓ │ +│ │ +│ Here's the configuration I added: │ +│ ```typescript │ +│ export default { │ +│ test: { globals: true } │ +│ } │ +│ ``` │ +└──────────────────────────────────────────┘ +```` + +**Tool Call (Collapsed):** + +``` +▶ bash: npm install vitest ✓ + ^ ^ ^ + | | | +Icon Tool name + summary Status +``` + +**Tool Call (Expanded):** + +``` +▼ bash: npm install vitest ✓ + + Input: + { + "command": "npm install vitest" + } + + Output: + added 50 packages, and audited 51 packages in 2s + found 0 vulnerabilities +``` + +**Status Icons:** + +- ⏳ Pending (spinner) +- ✓ Success (green checkmark) +- ✗ Error (red X) +- ⚠ Warning (yellow triangle) + +**File Change Display:** + +``` +▶ edit src/vitest.config.ts ✓ + Modified: src/vitest.config.ts + +12 lines, -3 lines +``` + +Click to expand: Show diff inline + +### 4. Controls Bar + +**Agent Selector:** + +- Dropdown button showing current agent +- Click: Opens dropdown with agent list +- Shows: Agent name + description +- Grouped by category (if applicable) + +**Model Selector:** + +- Dropdown button showing current model +- Click: Opens dropdown with model list +- Shows: Provider icon + Model name +- Grouped by provider +- Displays: Context window, capabilities icons + +**Layout:** + +``` +┌────────────────────────────────────────────┐ +│ Agent: Build ▼ Model: Claude 3.5 ▼ │ +└────────────────────────────────────────────┘ +``` + +### 5. Prompt Input + +**Input Field:** + +- Multi-line textarea +- Auto-expanding (max 10 lines) +- Placeholder: "Type your message or /command..." +- Supports keyboard shortcuts + +**Features:** + +**Slash Commands:** + +- Type `/` → Autocomplete dropdown appears +- Shows: Command name + description +- Filter as you type +- Enter to execute + +**File Mentions:** + +- Type `@` → File picker appears +- Search files by name +- Shows: File icon + path +- Enter to attach + +**Attachments:** + +- Display as chips above input +- Format: [@filename] [×] +- Click × to remove +- Drag & drop files onto input area + +**Send Button:** + +- Icon: Arrow (▶) or paper plane +- Click: Submit message +- Keyboard: Enter (without Shift) +- Disabled when: Empty input or server busy + +**Keyboard Shortcuts:** + +- Enter: New line +- Cmd+Enter (macOS) / Ctrl+Enter (Windows/Linux): Send message +- Cmd/Ctrl+K: Clear input +- Cmd/Ctrl+V: Paste (handles files) +- Cmd/Ctrl+L: Focus input +- Up/Down: Navigate message history (when input empty) + +## Overlays & Modals + +### Session Picker (Startup) + +Appears when instance starts: + +``` +┌────────────────────────────────────────┐ +│ OpenCode • ~/project-a │ +├────────────────────────────────────────┤ +│ Resume a session: │ +│ │ +│ > Fix login bug 2h ago │ +│ Add dark mode 5h ago │ +│ Refactor API Yesterday │ +│ │ +│ ────────────── or ────────────── │ +│ │ +│ Start new session: │ +│ Agent: [Build ▼] [Start] │ +│ │ +│ [Cancel] │ +└────────────────────────────────────────┘ +``` + +**Actions:** + +- Click session: Resume that session +- Click "Start": Create new session with selected agent +- Click "Cancel": Close instance +- Keyboard: Arrow keys to navigate, Enter to select + +### Confirmation Dialogs + +**Close Instance:** + +``` +┌────────────────────────────────────────┐ +│ Stop OpenCode instance? │ +├────────────────────────────────────────┤ +│ This will stop the server for: │ +│ ~/project-a │ +│ │ +│ Active sessions will be lost. │ +│ │ +│ [Cancel] [Stop Instance] │ +└────────────────────────────────────────┘ +``` + +**Delete Session:** + +``` +┌────────────────────────────────────────┐ +│ Delete session? │ +├────────────────────────────────────────┤ +│ This will permanently delete: │ +│ "Fix login bug" │ +│ │ +│ This cannot be undone. │ +│ │ +│ [Cancel] [Delete] │ +└────────────────────────────────────────┘ +``` + +## Empty States + +### No Instances + +``` +┌──────────────────────────────────────────┐ +│ │ +│ [Folder Icon] │ +│ │ +│ Start Coding with AI │ +│ │ +│ Select a folder to start coding with AI │ +│ │ +│ [Select Folder] │ +│ │ +│ Keyboard shortcut: Cmd/Ctrl+N │ +│ │ +└──────────────────────────────────────────┘ +``` + +### No Messages (New Session) + +``` +┌──────────────────────────────────────────┐ +│ │ +│ Start a conversation │ +│ │ +│ Type a message below or try: │ +│ • /init-project │ +│ • Ask about your codebase │ +│ • Attach files with @ │ +│ │ +└──────────────────────────────────────────┘ +``` + +### Logs Tab (No Logs Yet) + +``` +┌──────────────────────────────────────────┐ +│ Waiting for server output... │ +└──────────────────────────────────────────┘ +``` + +## Visual Styling + +### Color Scheme + +**Light Mode:** + +- Background: #FFFFFF +- Secondary background: #F5F5F5 +- Border: #E0E0E0 +- Text: #1A1A1A +- Muted text: #666666 +- Accent: #0066FF + +**Dark Mode:** + +- Background: #1A1A1A +- Secondary background: #2A2A2A +- Border: #3A3A3A +- Text: #E0E0E0 +- Muted text: #999999 +- Accent: #0080FF + +### Typography + +- **Main text**: 14px, system font +- **Headers**: 16px, medium weight +- **Labels**: 12px, regular weight +- **Code**: Monospace font (Consolas, Monaco, Courier) +- **Line height**: 1.5 + +### Spacing + +- **Padding**: 8px, 12px, 16px, 24px (consistent scale) +- **Margins**: Same as padding +- **Tab height**: 40px +- **Input height**: 80px (auto-expanding) +- **Message spacing**: 16px between messages + +### Icons + +- Use consistent icon set (Lucide, Heroicons, or similar) +- Size: 16px for inline, 20px for buttons +- Stroke width: 2px + +## Responsive Behavior + +### Minimum Window Size + +- Width: 800px +- Height: 600px + +### Behavior When Small + +- Instance tabs: Scroll horizontally +- Session tabs: Scroll horizontally +- Messages: Always visible, scroll vertically +- Input: Fixed at bottom + +## Accessibility + +- All interactive elements keyboard-navigable +- ARIA labels for screen readers +- Focus indicators visible +- Color contrast WCAG AA compliant +- Tab trap in modals +- Escape key closes overlays + +## Animation & Transitions + +- Tab switching: Instant (no animation) +- Message appearance: Fade in (100ms) +- Tool expand/collapse: Slide (200ms) +- Dropdown menus: Fade + slide (150ms) +- Loading states: Spinner or skeleton + +## Context Menus + +### Session Tab Right-Click + +- Rename +- Duplicate +- Share +- Export +- Delete +- Close Other Tabs + +### Message Right-Click + +- Copy message +- Copy code block +- Edit & regenerate +- Delete message +- Quote in reply + +## Status Indicators + +### Instance Tab + +- Green dot: Server running +- Yellow dot: Server starting +- Red dot: Server error +- No dot: Server stopped + +### Session Tab + +- Blue pulse: Assistant responding +- No indicator: Idle + +### Connection Status + +- Bottom right corner: "Connected" or "Reconnecting..." diff --git a/docs/screenshots/browser-support.png b/docs/screenshots/browser-support.png new file mode 100644 index 0000000..5bfb807 Binary files /dev/null and b/docs/screenshots/browser-support.png differ diff --git a/docs/screenshots/command-palette.png b/docs/screenshots/command-palette.png new file mode 100644 index 0000000..3847999 Binary files /dev/null and b/docs/screenshots/command-palette.png differ diff --git a/docs/screenshots/image-previews.png b/docs/screenshots/image-previews.png new file mode 100644 index 0000000..25bcd67 Binary files /dev/null and b/docs/screenshots/image-previews.png differ diff --git a/docs/screenshots/newSession.png b/docs/screenshots/newSession.png new file mode 100644 index 0000000..cb86e79 Binary files /dev/null and b/docs/screenshots/newSession.png differ diff --git a/images/CodeNomad-Icon-original.png b/images/CodeNomad-Icon-original.png new file mode 100644 index 0000000..9ce5d71 Binary files /dev/null and b/images/CodeNomad-Icon-original.png differ diff --git a/images/CodeNomad-Icon.png b/images/CodeNomad-Icon.png new file mode 100644 index 0000000..754b997 Binary files /dev/null and b/images/CodeNomad-Icon.png differ diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..a21fa89 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,9042 @@ +{ + "name": "codenomad-workspace", + "version": "0.4.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "codenomad-workspace", + "version": "0.4.0", + "dependencies": { + "7zip-bin": "^5.2.0", + "google-auth-library": "^10.5.0" + }, + "workspaces": { + "packages": [ + "packages/*" + ] + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.5", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@codenomad/tauri-app": { + "resolved": "packages/tauri-app", + "link": true + }, + "node_modules/@codenomad/ui": { + "resolved": "packages/ui", + "link": true + }, + "node_modules/@corvu/utils": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@corvu/utils/-/utils-0.4.2.tgz", + "integrity": "sha512-Ox2kYyxy7NoXdKWdHeDEjZxClwzO4SKM8plAaVwmAJPxHMqA0rLOoAsa+hBDwRLpctf+ZRnAd/ykguuJidnaTA==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.6.11" + }, + "peerDependencies": { + "solid-js": "^1.8" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@develar/schema-utils": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz", + "integrity": "sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.0", + "ajv-keywords": "^3.4.1" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/@electron/asar": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.4.1.tgz", + "integrity": "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^5.0.0", + "glob": "^7.1.6", + "minimatch": "^3.0.4" + }, + "bin": { + "asar": "bin/asar.js" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/@electron/asar/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@electron/asar/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@electron/get": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz", + "integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "env-paths": "^2.2.0", + "fs-extra": "^8.1.0", + "got": "^11.8.5", + "progress": "^2.0.3", + "semver": "^6.2.0", + "sumchecker": "^3.0.1" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "global-agent": "^3.0.0" + } + }, + "node_modules/@electron/notarize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.2.1.tgz", + "integrity": "sha512-aL+bFMIkpR0cmmj5Zgy0LMKEpgy43/hw5zadEArgmAMWWlKc5buwFvFT9G/o/YJkvXAJm5q3iuTuLaiaXW39sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.1", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/notarize/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/notarize/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/notarize/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/osx-sign": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@electron/osx-sign/-/osx-sign-1.0.5.tgz", + "integrity": "sha512-k9ZzUQtamSoweGQDV2jILiRIHUu7lYlJ3c6IEmjv1hC17rclE+eb9U+f6UFlOOETo0JzY1HNlXy4YOlCvl+Lww==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "compare-version": "^0.1.2", + "debug": "^4.3.4", + "fs-extra": "^10.0.0", + "isbinaryfile": "^4.0.8", + "minimist": "^1.2.6", + "plist": "^3.0.5" + }, + "bin": { + "electron-osx-flat": "bin/electron-osx-flat.js", + "electron-osx-sign": "bin/electron-osx-sign.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@electron/osx-sign/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@electron/osx-sign/node_modules/isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/@electron/osx-sign/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/osx-sign/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/universal": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@electron/universal/-/universal-1.5.1.tgz", + "integrity": "sha512-kbgXxyEauPJiQQUNG2VgUeyfQNFk6hBF11ISN2PNI6agUgPl55pv4eQmaqHzTAzchBvqZ2tQuRVaPStGf0mxGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron/asar": "^3.2.1", + "@malept/cross-spawn-promise": "^1.1.0", + "debug": "^4.3.1", + "dir-compare": "^3.0.0", + "fs-extra": "^9.0.1", + "minimatch": "^3.0.4", + "plist": "^3.0.4" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/@electron/universal/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@electron/universal/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/universal/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/universal/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@electron/universal/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@fastify/accept-negotiator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@fastify/accept-negotiator/-/accept-negotiator-1.1.0.tgz", + "integrity": "sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/@fastify/ajv-compiler": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-3.6.0.tgz", + "integrity": "sha512-LwdXQJjmMD+GwLOkP7TVC68qa+pSSogeWWmznRJ/coyTcfe9qA05AHFSe1eZFwK6q+xVRpChnvFUkf1iYaSZsQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.11.0", + "ajv-formats": "^2.1.1", + "fast-uri": "^2.0.0" + } + }, + "node_modules/@fastify/ajv-compiler/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@fastify/ajv-compiler/node_modules/ajv/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", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "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/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/@fastify/cors": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@fastify/cors/-/cors-8.5.0.tgz", + "integrity": "sha512-/oZ1QSb02XjP0IK1U0IXktEsw/dUBTxJOW7IpIeO8c/tNalw/KjoNSJv1Sf6eqoBPO+TDGkifq6ynFK3v68HFQ==", + "license": "MIT", + "dependencies": { + "fastify-plugin": "^4.0.0", + "mnemonist": "0.39.6" + } + }, + "node_modules/@fastify/error": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@fastify/error/-/error-3.4.1.tgz", + "integrity": "sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ==", + "license": "MIT" + }, + "node_modules/@fastify/fast-json-stringify-compiler": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-4.3.0.tgz", + "integrity": "sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==", + "license": "MIT", + "dependencies": { + "fast-json-stringify": "^5.7.0" + } + }, + "node_modules/@fastify/merge-json-schemas": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@fastify/merge-json-schemas/-/merge-json-schemas-0.1.1.tgz", + "integrity": "sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + } + }, + "node_modules/@fastify/reply-from": { + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/@fastify/reply-from/-/reply-from-9.8.0.tgz", + "integrity": "sha512-bPNVaFhEeNI0Lyl6404YZaPFokudCplidE3QoOcr78yOy6H9sYw97p5KPYvY/NJNUHfFtvxOaSAHnK+YSiv/Mg==", + "license": "MIT", + "dependencies": { + "@fastify/error": "^3.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", + "toad-cache": "^3.7.0", + "undici": "^5.19.1" + } + }, + "node_modules/@fastify/reply-from/node_modules/undici": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", + "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", + "license": "MIT", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/@fastify/send": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@fastify/send/-/send-2.1.0.tgz", + "integrity": "sha512-yNYiY6sDkexoJR0D8IDy3aRP3+L4wdqCpvx5WP+VtEU58sn7USmKynBzDQex5X42Zzvw2gNzzYgP90UfWShLFA==", + "license": "MIT", + "dependencies": { + "@lukeed/ms": "^2.0.1", + "escape-html": "~1.0.3", + "fast-decode-uri-component": "^1.0.1", + "http-errors": "2.0.0", + "mime": "^3.0.0" + } + }, + "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" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@fastify/static": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@fastify/static/-/static-7.0.4.tgz", + "integrity": "sha512-p2uKtaf8BMOZWLs6wu+Ihg7bWNBdjNgCwDza4MJtTqg+5ovKmcbgbR9Xs5/smZ1YISfzKOCNYmZV8LaCj+eJ1Q==", + "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" + } + }, + "node_modules/@fastify/static/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@fastify/static/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@fastify/static/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, + "node_modules/@git-diff-view/core": { + "version": "0.0.35", + "resolved": "https://registry.npmjs.org/@git-diff-view/core/-/core-0.0.35.tgz", + "integrity": "sha512-cdH3BopR6AWUW+6hP78zGyryKxR9JkPgryd1JN78i5k+F9Eo4x/4S23ZF1VZnrpPlGLrSuYfiAZ0ho5m+pTuKg==", + "license": "MIT", + "dependencies": { + "@git-diff-view/lowlight": "^0.0.35", + "fast-diff": "^1.3.0", + "highlight.js": "^11.11.0", + "lowlight": "^3.3.0" + } + }, + "node_modules/@git-diff-view/lowlight": { + "version": "0.0.35", + "resolved": "https://registry.npmjs.org/@git-diff-view/lowlight/-/lowlight-0.0.35.tgz", + "integrity": "sha512-MVpOxrNn1oHVOTOWUjxLbbf1W4OtVHjj6CHxwJbBRg9ZWZdShBINjuEgHVMSGB6vZuHKfwruRfXw8XxV3aF8zw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "highlight.js": "^11.11.0", + "lowlight": "^3.3.0" + } + }, + "node_modules/@git-diff-view/solid": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@git-diff-view/solid/-/solid-0.0.8.tgz", + "integrity": "sha512-MvZpyV5Gz0Axv2vvAlPpOmHtaJRUGBMoqXmvjIdZlUls0091QsglpE8bMbdRdEHuXodzxPDYyZrx3HCniMlGKw==", + "license": "MIT", + "dependencies": { + "@git-diff-view/core": "^0.0.35", + "@types/hast": "^3.0.0", + "fast-diff": "^1.3.0", + "highlight.js": "^11.11.0", + "lowlight": "^3.3.0", + "reactivity-store": "^0.3.12" + }, + "peerDependencies": { + "solid-js": "^1.9.0" + } + }, + "node_modules/@internationalized/date": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.10.0.tgz", + "integrity": "sha512-oxDR/NTEJ1k+UFVQElaNIk65E/Z83HK1z1WI3lQyhTtnNg4R5oVXaPzK3jcpKG8UHKDVuDQHzn+wsxSz8RP3aw==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, + "node_modules/@internationalized/number": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/@internationalized/number/-/number-3.6.5.tgz", + "integrity": "sha512-6hY4Kl4HPBvtfS62asS/R22JzNNy8vi/Ssev7x6EobfCp+9QIB2hKvI2EtbdJ0VSQacxVNtqhE/NmF/NZ0gm6g==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@kobalte/core": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/@kobalte/core/-/core-0.13.11.tgz", + "integrity": "sha512-hK7TYpdib/XDb/r/4XDBFaO9O+3ZHz4ZWryV4/3BfES+tSQVgg2IJupDnztKXB0BqbSRy/aWlHKw1SPtNPYCFQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.5.1", + "@internationalized/date": "^3.4.0", + "@internationalized/number": "^3.2.1", + "@kobalte/utils": "^0.9.1", + "@solid-primitives/props": "^3.1.8", + "@solid-primitives/resize-observer": "^2.0.26", + "solid-presence": "^0.1.8", + "solid-prevent-scroll": "^0.1.4" + }, + "peerDependencies": { + "solid-js": "^1.8.15" + } + }, + "node_modules/@kobalte/utils": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@kobalte/utils/-/utils-0.9.1.tgz", + "integrity": "sha512-eeU60A3kprIiBDAfv9gUJX1tXGLuZiKMajUfSQURAF2pk4ZoMYiqIzmrMBvzcxP39xnYttgTyQEVLwiTZnrV4w==", + "license": "MIT", + "dependencies": { + "@solid-primitives/event-listener": "^2.2.14", + "@solid-primitives/keyed": "^1.2.0", + "@solid-primitives/map": "^0.4.7", + "@solid-primitives/media": "^2.2.4", + "@solid-primitives/props": "^3.1.8", + "@solid-primitives/refs": "^1.0.5", + "@solid-primitives/utils": "^6.2.1" + }, + "peerDependencies": { + "solid-js": "^1.8.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" + } + }, + "node_modules/@malept/cross-spawn-promise": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz", + "integrity": "sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/malept" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" + } + ], + "license": "Apache-2.0", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@malept/flatpak-bundler": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@malept/flatpak-bundler/-/flatpak-bundler-0.4.0.tgz", + "integrity": "sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.0", + "lodash": "^4.17.15", + "tmp-promise": "^3.0.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@malept/flatpak-bundler/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@malept/flatpak-bundler/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@malept/flatpak-bundler/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@neuralnomads/codenomad": { + "resolved": "packages/server", + "link": true + }, + "node_modules/@neuralnomads/codenomad-electron-app": { + "resolved": "packages/electron-app", + "link": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@opencode-ai/sdk": { + "version": "1.0.138", + "resolved": "https://registry.npmjs.org/@opencode-ai/sdk/-/sdk-1.0.138.tgz", + "integrity": "sha512-9vXmpiAVVrhMZ3YNr7BGScyULFLyN0vnRx7iCDtN5qQDKxtsdQcXSQCz35XiVyD3A8lH5KOf5Zn0ByLYXuNeFQ==" + }, + "node_modules/@pinojs/redact": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", + "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==", + "license": "MIT" + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.5.tgz", + "integrity": "sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@shikijs/core": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.15.0.tgz", + "integrity": "sha512-8TOG6yG557q+fMsSVa8nkEDOZNTSxjbbR8l6lF2gyr6Np+jrPlslqDxQkN6rMXCECQ3isNPZAGszAfYoJOPGlg==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.15.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.5" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.15.0.tgz", + "integrity": "sha512-ZedbOFpopibdLmvTz2sJPJgns8Xvyabe2QbmqMTz07kt1pTzfEvKZc5IqPVO/XFiEbbNyaOpjPBkkr1vlwS+qg==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.15.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.3.3" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.15.0.tgz", + "integrity": "sha512-HnqFsV11skAHvOArMZdLBZZApRSYS4LSztk2K3016Y9VCyZISnlYUYsL2hzlS7tPqKHvNqmI5JSUJZprXloMvA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.15.0", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@shikijs/langs": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.15.0.tgz", + "integrity": "sha512-WpRvEFvkVvO65uKYW4Rzxs+IG0gToyM8SARQMtGGsH4GDMNZrr60qdggXrFOsdfOVssG/QQGEl3FnJ3EZ+8w8A==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.15.0" + } + }, + "node_modules/@shikijs/themes": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.15.0.tgz", + "integrity": "sha512-8ow2zWb1IDvCKjYb0KiLNrK4offFdkfNVPXb1OZykpLCzRU6j+efkY+Y7VQjNlNFXonSw+4AOdGYtmqykDbRiQ==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.15.0" + } + }, + "node_modules/@shikijs/types": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.15.0.tgz", + "integrity": "sha512-BnP+y/EQnhihgHy4oIAN+6FFtmfTekwOLsQbRw9hOKwqgNy8Bdsjq8B05oAt/ZgvIWWFrshV71ytOrlPfYjIJw==", + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "license": "MIT" + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@solid-primitives/event-listener": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/@solid-primitives/event-listener/-/event-listener-2.4.3.tgz", + "integrity": "sha512-h4VqkYFv6Gf+L7SQj+Y6puigL/5DIi7x5q07VZET7AWcS+9/G3WfIE9WheniHWJs51OEkRB43w6lDys5YeFceg==", + "license": "MIT", + "dependencies": { + "@solid-primitives/utils": "^6.3.2" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/keyed": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@solid-primitives/keyed/-/keyed-1.5.2.tgz", + "integrity": "sha512-BgoEdqPw48URnI+L5sZIHdF4ua4Las1eWEBBPaoSFs42kkhnHue+rwCBPL2Z9ebOyQ75sUhUfOETdJfmv0D6Kg==", + "license": "MIT", + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/map": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/@solid-primitives/map/-/map-0.4.13.tgz", + "integrity": "sha512-B1zyFbsiTQvqPr+cuPCXO72sRuczG9Swncqk5P74NCGw1VE8qa/Ry9GlfI1e/VdeQYHjan+XkbE3rO2GW/qKew==", + "license": "MIT", + "dependencies": { + "@solid-primitives/trigger": "^1.1.0" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/media": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@solid-primitives/media/-/media-2.3.3.tgz", + "integrity": "sha512-hQ4hLOGvfbugQi5Eu1BFWAIJGIAzztq9x0h02xgBGl2l0Jaa3h7tg6bz5tV1NSuNYVGio4rPoa7zVQQLkkx9dA==", + "license": "MIT", + "dependencies": { + "@solid-primitives/event-listener": "^2.4.3", + "@solid-primitives/rootless": "^1.5.2", + "@solid-primitives/static-store": "^0.1.2", + "@solid-primitives/utils": "^6.3.2" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/props": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@solid-primitives/props/-/props-3.2.2.tgz", + "integrity": "sha512-lZOTwFJajBrshSyg14nBMEP0h8MXzPowGO0s3OeiR3z6nXHTfj0FhzDtJMv+VYoRJKQHG2QRnJTgCzK6erARAw==", + "license": "MIT", + "dependencies": { + "@solid-primitives/utils": "^6.3.2" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@solid-primitives/refs/-/refs-1.1.2.tgz", + "integrity": "sha512-K7tf2thy7L+YJjdqXspXOg5xvNEOH8tgEWsp0+1mQk3obHBRD6hEjYZk7p7FlJphSZImS35je3UfmWuD7MhDfg==", + "license": "MIT", + "dependencies": { + "@solid-primitives/utils": "^6.3.2" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/resize-observer": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@solid-primitives/resize-observer/-/resize-observer-2.1.3.tgz", + "integrity": "sha512-zBLje5E06TgOg93S7rGPldmhDnouNGhvfZVKOp+oG2XU8snA+GoCSSCz1M+jpNAg5Ek2EakU5UVQqL152WmdXQ==", + "license": "MIT", + "dependencies": { + "@solid-primitives/event-listener": "^2.4.3", + "@solid-primitives/rootless": "^1.5.2", + "@solid-primitives/static-store": "^0.1.2", + "@solid-primitives/utils": "^6.3.2" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/rootless": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@solid-primitives/rootless/-/rootless-1.5.2.tgz", + "integrity": "sha512-9HULb0QAzL2r47CCad0M+NKFtQ+LrGGNHZfteX/ThdGvKIg2o2GYhBooZubTCd/RTu2l2+Nw4s+dEfiDGvdrrQ==", + "license": "MIT", + "dependencies": { + "@solid-primitives/utils": "^6.3.2" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/static-store": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@solid-primitives/static-store/-/static-store-0.1.2.tgz", + "integrity": "sha512-ReK+5O38lJ7fT+L6mUFvUr6igFwHBESZF+2Ug842s7fvlVeBdIVEdTCErygff6w7uR6+jrr7J8jQo+cYrEq4Iw==", + "license": "MIT", + "dependencies": { + "@solid-primitives/utils": "^6.3.2" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/trigger": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@solid-primitives/trigger/-/trigger-1.2.2.tgz", + "integrity": "sha512-IWoptVc0SWYgmpBPpCMehS5b07+tpFcvw15tOQ3QbXedSYn6KP8zCjPkHNzMxcOvOicTneleeZDP7lqmz+PQ6g==", + "license": "MIT", + "dependencies": { + "@solid-primitives/utils": "^6.3.2" + }, + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solid-primitives/utils": { + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/@solid-primitives/utils/-/utils-6.3.2.tgz", + "integrity": "sha512-hZ/M/qr25QOCcwDPOHtGjxTD8w2mNyVAYvcfgwzBHq2RwNqHNdDNsMZYap20+ruRwW4A3Cdkczyoz0TSxLCAPQ==", + "license": "MIT", + "peerDependencies": { + "solid-js": "^1.6.12" + } + }, + "node_modules/@solidjs/router": { + "version": "0.13.6", + "resolved": "https://registry.npmjs.org/@solidjs/router/-/router-0.13.6.tgz", + "integrity": "sha512-CdpFsBYoiJ/FQ4wZIamj3KEFRkmrYu5sVXM6PouNkmSENta1YJamsm9wa/VjaPmkw2RsnDnO0UvZ705v6EgOXQ==", + "license": "MIT", + "peerDependencies": { + "solid-js": "^1.8.6" + } + }, + "node_modules/@suid/base": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@suid/base/-/base-0.11.0.tgz", + "integrity": "sha512-jNe+LlXuxfkSZo8/MP9koqYYWswucDWSCwc7ViqUhQ0Y/V7sP2RiQ/Bnms+ePSMBZsk5k1b9fAjvj7DtNbbHXw==", + "license": "MIT", + "dependencies": { + "@popperjs/core": "^2.11.8", + "@suid/css": "0.4.1", + "@suid/system": "0.14.0", + "@suid/types": "0.8.0", + "@suid/utils": "0.11.0", + "clsx": "^2.1.1" + }, + "peerDependencies": { + "solid-js": "^1.9.7" + } + }, + "node_modules/@suid/css": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@suid/css/-/css-0.4.1.tgz", + "integrity": "sha512-Hsi4O3dBOm7rrlqKoWfNoTeRFAXm/7TPaeEmyxNx+wFaT3eROjMVdhadAIiagFT+PsHrq/6fDauUI5TkL+5Zvg==", + "license": "MIT" + }, + "node_modules/@suid/icons-material": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@suid/icons-material/-/icons-material-0.9.0.tgz", + "integrity": "sha512-2idgaT/JARd12dwDfocZBQizaiZVgR0ujRsVc61OlAuPZbeH+3TrSxUJkE3Z7+TPftw9+6p0A24GhJjJLvi6RQ==", + "license": "MIT", + "dependencies": { + "@suid/material": "0.19.0" + }, + "peerDependencies": { + "solid-js": "^1.9.7" + } + }, + "node_modules/@suid/material": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@suid/material/-/material-0.19.0.tgz", + "integrity": "sha512-vfudxYpHdur5CWTjd3eBb7q1b6A9X/pDWTEf2twc0gXVTcErS9VtY/VPBLa65AzO2SPJsdjAE+BCdVZiXASBbA==", + "license": "MIT", + "dependencies": { + "@suid/base": "0.11.0", + "@suid/css": "0.4.1", + "@suid/system": "0.14.0", + "@suid/types": "0.8.0", + "@suid/utils": "0.11.0", + "clsx": "^2.1.1" + }, + "peerDependencies": { + "solid-js": "^1.9.7" + } + }, + "node_modules/@suid/styled-engine": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@suid/styled-engine/-/styled-engine-0.9.0.tgz", + "integrity": "sha512-IfNHjQ3Im63mFIjFl/doiwdn5qbwgcwi/vUXnX7dmIUC/Cw1f3LPhzVT9V8Z3eqyvvFToy53O+BsuLy2e/WmDw==", + "license": "MIT", + "dependencies": { + "@suid/css": "0.4.1", + "@suid/utils": "0.11.0" + }, + "peerDependencies": { + "solid-js": "^1.9.7" + } + }, + "node_modules/@suid/system": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@suid/system/-/system-0.14.0.tgz", + "integrity": "sha512-aRVilPP53hHkqyAyQp2pasT/u8aQCcELwU4kFDnt3b+rj4fsPQRlhMumlX5mZ5aijIboH1CngU6TDG6Z9Mr3UA==", + "license": "MIT", + "dependencies": { + "@suid/css": "0.4.1", + "@suid/styled-engine": "0.9.0", + "@suid/types": "0.8.0", + "@suid/utils": "0.11.0", + "clsx": "^2.1.1", + "csstype": "^3.1.3" + }, + "peerDependencies": { + "solid-js": "^1.9.7" + } + }, + "node_modules/@suid/types": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@suid/types/-/types-0.8.0.tgz", + "integrity": "sha512-/Z2abkbypMjF6ygSpnjqnWohcmPqvgw8Xpx1wPPHeh+LajBP2imNT6uEa5dBqNEkJY8O3wEUCVqErAad/rmn5Q==", + "license": "MIT", + "peerDependencies": { + "solid-js": "^1.9.7" + } + }, + "node_modules/@suid/utils": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@suid/utils/-/utils-0.11.0.tgz", + "integrity": "sha512-dk+6YJkex9kcU2qQHCOk8J0/zkOKKbng0SsjC0LBLyBrf2OC3OtDQq7o22pH3m/8CU/0M6uyM7tnyzZA4eWF3Q==", + "license": "MIT", + "dependencies": { + "@suid/types": "0.8.0" + }, + "peerDependencies": { + "solid-js": "^1.9.7" + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", + "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@tauri-apps/cli": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.9.4.tgz", + "integrity": "sha512-pvylWC9QckrOS9ATWXIXcgu7g2hKK5xTL5ZQyZU/U0n9l88SEFGcWgLQNa8WZmd+wWIOWhkxOFcOl3i6ubDNNw==", + "dev": true, + "license": "Apache-2.0 OR MIT", + "bin": { + "tauri": "tauri.js" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "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" + } + }, + "node_modules/@tauri-apps/cli-darwin-arm64": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.9.4.tgz", + "integrity": "sha512-9rHkMVtbMhe0AliVbrGpzMahOBg3rwV46JYRELxR9SN6iu1dvPOaMaiC4cP6M/aD1424ziXnnMdYU06RAH8oIw==", + "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", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.9.4.tgz", + "integrity": "sha512-VT9ymNuT06f5TLjCZW2hfSxbVtZDhORk7CDUDYiq5TiSYQdxkl8MVBy0CCFFcOk4QAkUmqmVUA9r3YZ/N/vPRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.9.4.tgz", + "integrity": "sha512-tTWkEPig+2z3Rk0zqZYfjUYcgD+aSm72wdrIhdYobxbQZOBw0zfn50YtWv+av7bm0SHvv75f0l7JuwgZM1HFow==", + "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.9.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.9.4.tgz", + "integrity": "sha512-ql6vJ611qoqRYHxkKPnb2vHa27U+YRKRmIpLMMBeZnfFtZ938eao7402AQCH1mO2+/8ioUhbpy9R/ZcLTXVmkg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-musl": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.9.4.tgz", + "integrity": "sha512-vg7yNn7ICTi6hRrcA/6ff2UpZQP7un3xe3SEld5QM0prgridbKAiXGaCKr3BnUBx/rGXegQlD/wiLcWdiiraSw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-riscv64-gnu": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.9.4.tgz", + "integrity": "sha512-l8L+3VxNk6yv5T/Z/gv5ysngmIpsai40B9p6NQQyqYqxImqYX37pqREoEBl1YwG7szGnDibpWhidPrWKR59OJA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-gnu": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.9.4.tgz", + "integrity": "sha512-PepPhCXc/xVvE3foykNho46OmCyx47E/aG676vKTVp+mqin5d+IBqDL6wDKiGNT5OTTxKEyNlCQ81Xs2BQhhqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-musl": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.9.4.tgz", + "integrity": "sha512-zcd1QVffh5tZs1u1SCKUV/V7RRynebgYUNWHuV0FsIF1MjnULUChEXhAhug7usCDq4GZReMJOoXa6rukEozWIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-arm64-msvc": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.9.4.tgz", + "integrity": "sha512-/7ZhnP6PY04bEob23q8MH/EoDISdmR1wuNm0k9d5HV7TDMd2GGCDa8dPXA4vJuglJKXIfXqxFmZ4L+J+MO42+w==", + "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.9.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.9.4.tgz", + "integrity": "sha512-1LmAfaC4Cq+3O1Ir1ksdhczhdtFSTIV51tbAGtbV/mr348O+M52A/xwCCXQank0OcdBxy5BctqkMtuZnQvA8uQ==", + "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==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/fs-extra": { + "version": "9.0.13", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", + "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.19.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.0.tgz", + "integrity": "sha512-xpr/lmLPQEj+TUnHmR+Ab91/glhJvsqcjB+yY0Ix9GO70H6Lb4FHH5GeqdOE5btAx7eIMwuHkp4H2MSkLcqWbA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/plist": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/plist/-/plist-3.0.5.tgz", + "integrity": "sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*", + "xmlbuilder": ">=11.0.1" + } + }, + "node_modules/@types/responselike": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", + "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@types/verror": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.11.tgz", + "integrity": "sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "license": "ISC" + }, + "node_modules/@vue/reactivity": { + "version": "3.5.24", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.24.tgz", + "integrity": "sha512-BM8kBhtlkkbnyl4q+HiF5R5BL0ycDPfihowulm02q3WYp2vxgPcJuZO866qa/0u3idbMntKEtVNuAUp5bw4teg==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.24" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.24", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.24.tgz", + "integrity": "sha512-9cwHL2EsJBdi8NY22pngYYWzkTDhld6fAD6jlaeloNGciNSJL6bLpbxVgXl96X00Jtc6YWQv96YA/0sxex/k1A==", + "license": "MIT" + }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.11", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz", + "integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/7zip-bin": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.2.0.tgz", + "integrity": "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==", + "license": "MIT" + }, + "node_modules/abstract-logging": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz", + "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==", + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/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", + "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": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/app-builder-bin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-4.0.0.tgz", + "integrity": "sha512-xwdG0FJPQMe0M0UA4Tz0zEB8rBJTRA5a476ZawAqiBkMv16GRK5xpXThOjMaEOFnZ6zabejjG4J3da0SXG63KA==", + "dev": true, + "license": "MIT" + }, + "node_modules/app-builder-lib": { + "version": "24.13.3", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-24.13.3.tgz", + "integrity": "sha512-FAzX6IBit2POXYGnTCT8YHFO/lr5AapAII6zzhQO3Rw4cEDOgK+t1xhLc5tNcKlicTHlo9zxIwnYCX9X2DLkig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@develar/schema-utils": "~2.6.5", + "@electron/notarize": "2.2.1", + "@electron/osx-sign": "1.0.5", + "@electron/universal": "1.5.1", + "@malept/flatpak-bundler": "^0.4.0", + "@types/fs-extra": "9.0.13", + "async-exit-hook": "^2.0.1", + "bluebird-lst": "^1.0.9", + "builder-util": "24.13.1", + "builder-util-runtime": "9.2.4", + "chromium-pickle-js": "^0.2.0", + "debug": "^4.3.4", + "ejs": "^3.1.8", + "electron-publish": "24.13.1", + "form-data": "^4.0.0", + "fs-extra": "^10.1.0", + "hosted-git-info": "^4.1.0", + "is-ci": "^3.0.0", + "isbinaryfile": "^5.0.0", + "js-yaml": "^4.1.0", + "lazy-val": "^1.0.5", + "minimatch": "^5.1.1", + "read-config-file": "6.3.2", + "sanitize-filename": "^1.6.3", + "semver": "^7.3.8", + "tar": "^6.1.12", + "temp-file": "^3.4.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "dmg-builder": "24.13.3", + "electron-builder-squirrel-windows": "24.13.3" + } + }, + "node_modules/app-builder-lib/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/app-builder-lib/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/app-builder-lib/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/app-builder-lib/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/archiver": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", + "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "archiver-utils": "^2.1.0", + "async": "^3.2.4", + "buffer-crc32": "^0.2.1", + "readable-stream": "^3.6.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^2.2.0", + "zip-stream": "^4.1.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/archiver-utils/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/archiver-utils/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/archiver-utils/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-exit-hook": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", + "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.21", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", + "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.24.4", + "caniuse-lite": "^1.0.30001702", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/avvio": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/avvio/-/avvio-8.4.0.tgz", + "integrity": "sha512-CDSwaxINFy59iNwhYnkvALBwZiTydGkOecZyPkqBpABYR1KqGEsET0VOOYDwtleZSUIdeY36DC2bSZ24CO1igA==", + "license": "MIT", + "dependencies": { + "@fastify/error": "^3.3.0", + "fastq": "^1.17.1" + } + }, + "node_modules/babel-plugin-jsx-dom-expressions": { + "version": "0.40.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jsx-dom-expressions/-/babel-plugin-jsx-dom-expressions-0.40.3.tgz", + "integrity": "sha512-5HOwwt0BYiv/zxl7j8Pf2bGL6rDXfV6nUhLs8ygBX+EFJXzBPHM/euj9j/6deMZ6wa52Wb2PBaAV5U/jKwIY1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "7.18.6", + "@babel/plugin-syntax-jsx": "^7.18.6", + "@babel/types": "^7.20.7", + "html-entities": "2.3.3", + "parse5": "^7.1.2" + }, + "peerDependencies": { + "@babel/core": "^7.20.12" + } + }, + "node_modules/babel-plugin-jsx-dom-expressions/node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/babel-preset-solid": { + "version": "1.9.10", + "resolved": "https://registry.npmjs.org/babel-preset-solid/-/babel-preset-solid-1.9.10.tgz", + "integrity": "sha512-HCelrgua/Y+kqO8RyL04JBWS/cVdrtUv/h45GntgQY+cJl4eBcKkCDV3TdMjtKx1nXwRaR9QXslM/Npm1dxdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jsx-dom-expressions": "^0.40.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "solid-js": "^1.9.10" + }, + "peerDependenciesMeta": { + "solid-js": { + "optional": true + } + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.25", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.25.tgz", + "integrity": "sha512-2NovHVesVF5TXefsGX1yzx1xgr7+m9JQenvz6FQY3qd+YXkKkYiv+vTCc7OriP9mcDZpTC5mAOYN4ocd29+erA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/bluebird-lst": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/bluebird-lst/-/bluebird-lst-1.0.9.tgz", + "integrity": "sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bluebird": "^3.5.5" + } + }, + "node_modules/boolean": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", + "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.27.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.27.0.tgz", + "integrity": "sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "baseline-browser-mapping": "^2.8.19", + "caniuse-lite": "^1.0.30001751", + "electron-to-chromium": "^1.5.238", + "node-releases": "^2.0.26", + "update-browserslist-db": "^1.1.4" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.1.tgz", + "integrity": "sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/builder-util": { + "version": "24.13.1", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-24.13.1.tgz", + "integrity": "sha512-NhbCSIntruNDTOVI9fdXz0dihaqX2YuE1D6zZMrwiErzH4ELZHE6mdiB40wEgZNprDia+FghRFgKoAqMZRRjSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/debug": "^4.1.6", + "7zip-bin": "~5.2.0", + "app-builder-bin": "4.0.0", + "bluebird-lst": "^1.0.9", + "builder-util-runtime": "9.2.4", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "debug": "^4.3.4", + "fs-extra": "^10.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-ci": "^3.0.0", + "js-yaml": "^4.1.0", + "source-map-support": "^0.5.19", + "stat-mode": "^1.0.0", + "temp-file": "^3.4.0" + } + }, + "node_modules/builder-util-runtime": { + "version": "9.2.4", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.4.tgz", + "integrity": "sha512-upp+biKpN/XZMLim7aguUyW8s0FUpDvOtK6sbanMFDAMBzpHDqdhgVYm6zc9HJ6nWo7u2Lxk60i2M6Jd3aiNrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/builder-util/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/builder-util/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/builder-util/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001754", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001754.tgz", + "integrity": "sha512-x6OeBXueoAceOmotzx3PO4Zpt4rzpeIFsSr6AAePTZxSkXiYDUmpypEl7e2+8NCd9bD7bXjqyef8CJYPC1jfxg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/chromium-pickle-js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz", + "integrity": "sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/compare-version": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", + "integrity": "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/compress-commons": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz", + "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^4.0.2", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/config-file-ts": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/config-file-ts/-/config-file-ts-0.2.6.tgz", + "integrity": "sha512-6boGVaglwblBgJqGyxm4+xCmEGcWgnWHSWHY5jad58awQhB6gftq0G8HbzU39YqCIYHMLAiL1yjwiZ36m/CL8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "^10.3.10", + "typescript": "^5.3.3" + } + }, + "node_modules/config-file-ts/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/config-file-ts/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/config-file-ts/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/crc": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", + "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "buffer": "^5.1.0" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz", + "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^3.4.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "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" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dijkstrajs": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", + "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==", + "license": "MIT" + }, + "node_modules/dir-compare": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-3.3.0.tgz", + "integrity": "sha512-J7/et3WlGUCxjdnD3HAAzQ6nsnc0WL6DD7WcwJb7c39iH1+AWfg+9OqzJNaI6PkBwBvm1mhZNL9iY/nRiZXlPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-equal": "^1.0.0", + "minimatch": "^3.0.4" + } + }, + "node_modules/dir-compare/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/dir-compare/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true, + "license": "MIT" + }, + "node_modules/dmg-builder": { + "version": "24.13.3", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-24.13.3.tgz", + "integrity": "sha512-rcJUkMfnJpfCboZoOOPf4L29TRtEieHNOeAbYPWPxlaBw/Z1RKrRA86dOI9rwaI4tQSc/RD82zTNHprfUHXsoQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "app-builder-lib": "24.13.3", + "builder-util": "24.13.1", + "builder-util-runtime": "9.2.4", + "fs-extra": "^10.1.0", + "iconv-lite": "^0.6.2", + "js-yaml": "^4.1.0" + }, + "optionalDependencies": { + "dmg-license": "^1.0.11" + } + }, + "node_modules/dmg-builder/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dmg-builder/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/dmg-builder/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/dmg-license": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.11.tgz", + "integrity": "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "@types/plist": "^3.0.1", + "@types/verror": "^1.10.3", + "ajv": "^6.10.0", + "crc": "^3.8.0", + "iconv-corefoundation": "^1.1.7", + "plist": "^3.0.4", + "smart-buffer": "^4.0.2", + "verror": "^1.10.0" + }, + "bin": { + "dmg-license": "bin/dmg-license.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-9.0.2.tgz", + "integrity": "sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=10" + } + }, + "node_modules/dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron": { + "version": "39.0.0", + "resolved": "https://registry.npmjs.org/electron/-/electron-39.0.0.tgz", + "integrity": "sha512-UejnuOK4jpRZUq7MkEAnR/szsRWLKBJAdvn6j3xdQLT57fVv13VSNdaUHHjSheaqGzNhCGIdkPsPJnGJVh5kiA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@electron/get": "^2.0.0", + "@types/node": "^22.7.7", + "extract-zip": "^2.0.1" + }, + "bin": { + "electron": "cli.js" + }, + "engines": { + "node": ">= 12.20.55" + } + }, + "node_modules/electron-builder": { + "version": "24.13.3", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-24.13.3.tgz", + "integrity": "sha512-yZSgVHft5dNVlo31qmJAe4BVKQfFdwpRw7sFp1iQglDRCDD6r22zfRJuZlhtB5gp9FHUxCMEoWGq10SkCnMAIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "app-builder-lib": "24.13.3", + "builder-util": "24.13.1", + "builder-util-runtime": "9.2.4", + "chalk": "^4.1.2", + "dmg-builder": "24.13.3", + "fs-extra": "^10.1.0", + "is-ci": "^3.0.0", + "lazy-val": "^1.0.5", + "read-config-file": "6.3.2", + "simple-update-notifier": "2.0.0", + "yargs": "^17.6.2" + }, + "bin": { + "electron-builder": "cli.js", + "install-app-deps": "install-app-deps.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/electron-builder-squirrel-windows": { + "version": "24.13.3", + "resolved": "https://registry.npmjs.org/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-24.13.3.tgz", + "integrity": "sha512-oHkV0iogWfyK+ah9ZIvMDpei1m9ZRpdXcvde1wTpra2U8AFDNNpqJdnin5z+PM1GbQ5BoaKCWas2HSjtR0HwMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "app-builder-lib": "24.13.3", + "archiver": "^5.3.1", + "builder-util": "24.13.1", + "fs-extra": "^10.1.0" + } + }, + "node_modules/electron-builder-squirrel-windows/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-builder-squirrel-windows/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-builder-squirrel-windows/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron-builder/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-builder/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-builder/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron-publish": { + "version": "24.13.1", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-24.13.1.tgz", + "integrity": "sha512-2ZgdEqJ8e9D17Hwp5LEq5mLQPjqU3lv/IALvgp+4W8VeNhryfGhYEQC/PgDPMrnWUp+l60Ou5SJLsu+k4mhQ8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/fs-extra": "^9.0.11", + "builder-util": "24.13.1", + "builder-util-runtime": "9.2.4", + "chalk": "^4.1.2", + "fs-extra": "^10.1.0", + "lazy-val": "^1.0.5", + "mime": "^2.5.2" + } + }, + "node_modules/electron-publish/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-publish/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-publish/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.247", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.247.tgz", + "integrity": "sha512-bCkfEJNE5EOhEsGpgbvgUAXYP/uAZeN9GCd9bPGjm2/uiLdpoiZnxrBTbWT1nbZs1y6UqN7hatM3hOB4X1kXUQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/electron-vite": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/electron-vite/-/electron-vite-4.0.1.tgz", + "integrity": "sha512-QqacJbA8f1pmwUTqki1qLL5vIBaOQmeq13CZZefZ3r3vKVaIoC7cpoTgE+KPKxJDFTax+iFZV0VYvLVWPiQ8Aw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.7", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "cac": "^6.7.14", + "esbuild": "^0.25.5", + "magic-string": "^0.30.17", + "picocolors": "^1.1.1" + }, + "bin": { + "electron-vite": "bin/electron-vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@swc/core": "^1.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + } + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-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": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extsprintf": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz", + "integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "license": "MIT", + "optional": true + }, + "node_modules/fast-content-type-parse": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-1.1.0.tgz", + "integrity": "sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==", + "license": "MIT" + }, + "node_modules/fast-decode-uri-component": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", + "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "license": "Apache-2.0" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stringify": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-5.16.1.tgz", + "integrity": "sha512-KAdnLvy1yu/XrRtP+LJnxbBGrhN+xXu+gt3EUvZhYGKCr3lFHq/7UFJHHFgmJKoqlh6B40bZLEv7w46B0mqn1g==", + "license": "MIT", + "dependencies": { + "@fastify/merge-json-schemas": "^0.1.0", + "ajv": "^8.10.0", + "ajv-formats": "^3.0.1", + "fast-deep-equal": "^3.1.3", + "fast-uri": "^2.1.0", + "json-schema-ref-resolver": "^1.0.1", + "rfdc": "^1.2.0" + } + }, + "node_modules/fast-json-stringify/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/fast-json-stringify/node_modules/ajv-formats": { + "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" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/fast-json-stringify/node_modules/ajv/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", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "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", + "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz", + "integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==", + "license": "MIT", + "dependencies": { + "fast-decode-uri-component": "^1.0.1" + } + }, + "node_modules/fast-uri": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-2.4.0.tgz", + "integrity": "sha512-ypuAmmMKInk5q7XcepxlnUWDLWv4GFtaJqAzWKqn62IpQ3pejtr5dTVbt3vwqVaMKmkNR55sTT+CqUKIaT21BA==", + "license": "MIT" + }, + "node_modules/fastify": { + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/fastify/-/fastify-4.29.1.tgz", + "integrity": "sha512-m2kMNHIG92tSNWv+Z3UeTR9AWLLuo7KctC7mlFPtMEVrfjIhmQhkQnT9v15qA/BfVq3vvj134Y0jl9SBje3jXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "@fastify/ajv-compiler": "^3.5.0", + "@fastify/error": "^3.4.0", + "@fastify/fast-json-stringify-compiler": "^4.3.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" + } + }, + "node_modules/fastify-plugin": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-4.5.1.tgz", + "integrity": "sha512-stRHYGeuqpEZTL1Ef0Ovr2ltazUT9g844X5z/zEBFLG8RYlpDiOCIG+ATvYEp+/zmc7sN29mcIMp8gvYplYPIQ==", + "license": "MIT" + }, + "node_modules/fastify/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-my-way": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-8.2.2.tgz", + "integrity": "sha512-Dobi7gcTEq8yszimcfp/R7+owiT4WncAJ7VTTgFH1jYJ5GaG1FbhjwDG820hptN0QDFvzVY3RfCzdInvGPGzjA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-querystring": "^1.0.0", + "safe-regex2": "^3.1.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true, + "license": "MIT" + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gaxios": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.3.tgz", + "integrity": "sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2", + "rimraf": "^5.0.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/gaxios/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/gaxios/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/gcp-metadata": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", + "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^7.0.0", + "google-logging-utils": "^1.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/github-markdown-css": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/github-markdown-css/-/github-markdown-css-5.8.1.tgz", + "integrity": "sha512-8G+PFvqigBQSWLQjyzgpa2ThD9bo7+kDsriUIidGcRhXgmcaAWUIpCZf8DavJgc+xifjbCG+GvMyWr0XMXmc7g==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/global-agent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", + "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "es6-error": "^4.1.1", + "matcher": "^3.0.0", + "roarr": "^2.15.3", + "semver": "^7.3.2", + "serialize-error": "^7.0.1" + }, + "engines": { + "node": ">=10.0" + } + }, + "node_modules/global-agent/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/google-auth-library": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.5.0.tgz", + "integrity": "sha512-7ABviyMOlX5hIVD60YOfHw4/CxOfBhyduaYB+wbFWCWoni4N7SLcV46hrVRktuBbZjFC9ONyqamZITN7q3n32w==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^7.0.0", + "gcp-metadata": "^8.0.0", + "google-logging-utils": "^1.0.0", + "gtoken": "^8.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/google-logging-utils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", + "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/gtoken": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-8.0.0.tgz", + "integrity": "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==", + "license": "MIT", + "dependencies": { + "gaxios": "^7.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/highlight.js": { + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", + "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/html-entities": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", + "dev": true, + "license": "MIT" + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/iconv-corefoundation": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", + "integrity": "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "cli-truncate": "^2.1.0", + "node-addon-api": "^1.6.3" + }, + "engines": { + "node": "^8.11.2 || >=10" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-what": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", + "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isbinaryfile": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-5.0.6.tgz", + "integrity": "sha512-I+NmIfBHUl+r2wcDd6JwE9yWje/PIVY/R5/CmV8dXLZd5K+L9X2klAOwfAHNnondLXkbHyTAleQAWonpTJBTtw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jake": { + "version": "10.9.4", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.6", + "filelist": "^1.0.4", + "picocolors": "^1.1.1" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-ref-resolver": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-schema-ref-resolver/-/json-schema-ref-resolver-1.0.1.tgz", + "integrity": "sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/lazy-val": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz", + "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lazystream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/light-my-request": { + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-5.14.0.tgz", + "integrity": "sha512-aORPWntbpH5esaYpGOOmri0OHDOe3wC5M2MQxZ9dvMLZm6DnaAn0kJlcbU9hwsQgLzmZyReKwFwwPkR+nHu5kA==", + "license": "BSD-3-Clause", + "dependencies": { + "cookie": "^0.7.0", + "process-warning": "^3.0.0", + "set-cookie-parser": "^2.4.1" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/lowlight": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-3.3.0.tgz", + "integrity": "sha512-0JNhgFoPvP6U6lE/UdVsSq99tn6DhjjpAj5MxG49ewd2mOBVtwWYIT8ClyABhq198aXXODMU6Ox8DrGy/CpTZQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.0.0", + "highlight.js": "~11.11.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-solid": { + "version": "0.300.0", + "resolved": "https://registry.npmjs.org/lucide-solid/-/lucide-solid-0.300.0.tgz", + "integrity": "sha512-FEAF0CYnuhQiFjpZe2UxQ0LX/wJFuPvFlyVwDdD4uvvAP/nzhCa1xSMhMBpaCTH3BIveJvoz14YOl7uiLkZYow==", + "license": "ISC", + "peerDependencies": { + "solid-js": "^1.4.7" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/marked": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.2.tgz", + "integrity": "sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/matcher": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", + "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "escape-string-regexp": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/merge-anything": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/merge-anything/-/merge-anything-5.1.7.tgz", + "integrity": "sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-what": "^4.1.8" + }, + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mnemonist": { + "version": "0.39.6", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.39.6.tgz", + "integrity": "sha512-A/0v5Z59y63US00cRSLiloEIw3t5G+MiKz4BhX21FI+YBJXBOGW0ohFxTxO08dsOYlzxo87T7vGfZKYp2bcAWA==", + "license": "MIT", + "dependencies": { + "obliterator": "^2.0.1" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-addon-api": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", + "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/obliterator": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.5.tgz", + "integrity": "sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==", + "license": "MIT" + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/oniguruma-parser": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.1.tgz", + "integrity": "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==", + "license": "MIT" + }, + "node_modules/oniguruma-to-es": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.3.tgz", + "integrity": "sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg==", + "license": "MIT", + "dependencies": { + "oniguruma-parser": "^0.12.1", + "regex": "^6.0.1", + "regex-recursion": "^6.0.2" + } + }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pino": { + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-9.14.0.tgz", + "integrity": "sha512-8OEwKp5juEvb/MjpIc4hjqfgCNysrS94RIOMXYvpYCdm/jglrKEiAYmiumbmGhCvs+IcInsphYDFwqrjr7398w==", + "license": "MIT", + "dependencies": { + "@pinojs/redact": "^0.4.0", + "atomic-sleep": "^1.0.0", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^2.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^3.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz", + "integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==", + "license": "MIT", + "dependencies": { + "split2": "^4.0.0" + } + }, + "node_modules/pino-std-serializers": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz", + "integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==", + "license": "MIT" + }, + "node_modules/pino/node_modules/process-warning": { + "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/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/plist": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", + "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + }, + "engines": { + "node": ">=10.4.0" + } + }, + "node_modules/png2icons": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/png2icons/-/png2icons-2.0.1.tgz", + "integrity": "sha512-GDEQJr8OG4e6JMp7mABtXFSEpgJa1CCpbQiAR+EjhkHJHnUL9zPPtbOrjsMD8gUbikgv3j7x404b0YJsV3aVFA==", + "dev": true, + "license": "MIT", + "bin": { + "png2icons": "png2icons-cli.js" + } + }, + "node_modules/pngjs": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz", + "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.19.0" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/process-warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", + "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==", + "license": "MIT" + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qrcode": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz", + "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==", + "license": "MIT", + "dependencies": { + "dijkstrajs": "^1.0.1", + "pngjs": "^5.0.0", + "yargs": "^15.3.1" + }, + "bin": { + "qrcode": "bin/qrcode" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/qrcode/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/qrcode/node_modules/pngjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/qrcode/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "license": "ISC" + }, + "node_modules/qrcode/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "license": "MIT" + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", + "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/reactivity-store": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/reactivity-store/-/reactivity-store-0.3.12.tgz", + "integrity": "sha512-Idz9EL4dFUtQbHySZQzckWOTUfqjdYpUtNW0iOysC32mG7IjiUGB77QrsyR5eAWBkRiS9JscF6A3fuQAIy+LrQ==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "~3.5.22", + "@vue/shared": "~3.5.22", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/read-config-file": { + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/read-config-file/-/read-config-file-6.3.2.tgz", + "integrity": "sha512-M80lpCjnE6Wt6zb98DoW8WHR09nzMSpu8XHtPkiTHrJ5Az9CybfeQhTJ8D7saeBHpGhLPIVyA8lcL6ZmdKwY6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "config-file-ts": "^0.2.4", + "dotenv": "^9.0.2", + "dotenv-expand": "^5.1.0", + "js-yaml": "^4.1.0", + "json5": "^2.2.0", + "lazy-val": "^1.0.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.1.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.0.1.tgz", + "integrity": "sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "license": "ISC" + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ret": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.4.3.tgz", + "integrity": "sha512-0f4Memo5QP7WQyUEAYUO3esD/XjOc3Zjjg5CPsAq1p8sIu0XPeMbHJemKA0BO7tV0X7+A0FoEpbmHXWxPyD3wQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "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": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", + "license": "ISC", + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/roarr": { + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", + "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "detect-node": "^2.0.4", + "globalthis": "^1.0.1", + "json-stringify-safe": "^5.0.1", + "semver-compare": "^1.0.0", + "sprintf-js": "^1.1.2" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/rollup": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz", + "integrity": "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.52.5", + "@rollup/rollup-android-arm64": "4.52.5", + "@rollup/rollup-darwin-arm64": "4.52.5", + "@rollup/rollup-darwin-x64": "4.52.5", + "@rollup/rollup-freebsd-arm64": "4.52.5", + "@rollup/rollup-freebsd-x64": "4.52.5", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.5", + "@rollup/rollup-linux-arm-musleabihf": "4.52.5", + "@rollup/rollup-linux-arm64-gnu": "4.52.5", + "@rollup/rollup-linux-arm64-musl": "4.52.5", + "@rollup/rollup-linux-loong64-gnu": "4.52.5", + "@rollup/rollup-linux-ppc64-gnu": "4.52.5", + "@rollup/rollup-linux-riscv64-gnu": "4.52.5", + "@rollup/rollup-linux-riscv64-musl": "4.52.5", + "@rollup/rollup-linux-s390x-gnu": "4.52.5", + "@rollup/rollup-linux-x64-gnu": "4.52.5", + "@rollup/rollup-linux-x64-musl": "4.52.5", + "@rollup/rollup-openharmony-arm64": "4.52.5", + "@rollup/rollup-win32-arm64-msvc": "4.52.5", + "@rollup/rollup-win32-ia32-msvc": "4.52.5", + "@rollup/rollup-win32-x64-gnu": "4.52.5", + "@rollup/rollup-win32-x64-msvc": "4.52.5", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-regex2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-3.1.0.tgz", + "integrity": "sha512-RAAZAGbap2kBfbVhvmnTFv73NWLMvDGOITFYTZBAaY8eR+Ir4ef7Up/e7amo+y1+AH+3PtLkrt9mvcTsG9LXug==", + "license": "MIT", + "dependencies": { + "ret": "~0.4.0" + } + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/sanitize-filename": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz", + "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==", + "dev": true, + "license": "WTFPL OR ISC", + "dependencies": { + "truncate-utf8-bytes": "^1.0.0" + } + }, + "node_modules/sax": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.3.tgz", + "integrity": "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/secure-json-parse": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", + "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==", + "license": "BSD-3-Clause" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/serialize-error": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", + "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "type-fest": "^0.13.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/seroval": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.3.2.tgz", + "integrity": "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/seroval-plugins": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.3.3.tgz", + "integrity": "sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "seroval": "^1.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC" + }, + "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/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shiki": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.15.0.tgz", + "integrity": "sha512-kLdkY6iV3dYbtPwS9KXU7mjfmDm25f5m0IPNFnaXO7TBPcvbUOY72PYXSuSqDzwp+vlH/d7MXpHlKO/x+QoLXw==", + "license": "MIT", + "dependencies": { + "@shikijs/core": "3.15.0", + "@shikijs/engine-javascript": "3.15.0", + "@shikijs/engine-oniguruma": "3.15.0", + "@shikijs/langs": "3.15.0", + "@shikijs/themes": "3.15.0", + "@shikijs/types": "3.15.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/solid-js": { + "version": "1.9.10", + "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.10.tgz", + "integrity": "sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew==", + "license": "MIT", + "peer": true, + "dependencies": { + "csstype": "^3.1.0", + "seroval": "~1.3.0", + "seroval-plugins": "~1.3.0" + } + }, + "node_modules/solid-presence": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/solid-presence/-/solid-presence-0.1.8.tgz", + "integrity": "sha512-pWGtXUFWYYUZNbg5YpG5vkQJyOtzn2KXhxYaMx/4I+lylTLYkITOLevaCwMRN+liCVk0pqB6EayLWojNqBFECA==", + "license": "MIT", + "dependencies": { + "@corvu/utils": "~0.4.0" + }, + "peerDependencies": { + "solid-js": "^1.8" + } + }, + "node_modules/solid-prevent-scroll": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/solid-prevent-scroll/-/solid-prevent-scroll-0.1.10.tgz", + "integrity": "sha512-KplGPX2GHiWJLZ6AXYRql4M127PdYzfwvLJJXMkO+CMb8Np4VxqDAg5S8jLdwlEuBis/ia9DKw2M8dFx5u8Mhw==", + "license": "MIT", + "dependencies": { + "@corvu/utils": "~0.4.1" + }, + "peerDependencies": { + "solid-js": "^1.8" + } + }, + "node_modules/solid-refresh": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/solid-refresh/-/solid-refresh-0.6.3.tgz", + "integrity": "sha512-F3aPsX6hVw9ttm5LYlth8Q15x6MlI/J3Dn+o3EQyRTtTxidepSTwAYdozt01/YA+7ObcciagGEyXIopGZzQtbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/generator": "^7.23.6", + "@babel/helper-module-imports": "^7.22.15", + "@babel/types": "^7.23.6" + }, + "peerDependencies": { + "solid-js": "^1.3" + } + }, + "node_modules/solid-toast": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/solid-toast/-/solid-toast-0.5.0.tgz", + "integrity": "sha512-t770JakjyS2P9b8Qa1zMLOD51KYKWXbTAyJePVUoYex5c5FH5S/HtUBUbZAWFcqRCKmAE8KhyIiCvDZA8bOnxQ==", + "license": "MIT", + "peerDependencies": { + "solid-js": "^1.5.4" + } + }, + "node_modules/sonic-boom": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.0.tgz", + "integrity": "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/stat-mode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-1.0.0.tgz", + "integrity": "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/sucrase/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sucrase/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sucrase/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/sumchecker": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", + "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.1.0" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.18", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.18.tgz", + "integrity": "sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dev": true, + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/temp-file": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.4.0.tgz", + "integrity": "sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-exit-hook": "^2.0.1", + "fs-extra": "^10.0.0" + } + }, + "node_modules/temp-file/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/temp-file/node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/temp-file/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/thread-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz", + "integrity": "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==", + "license": "MIT", + "dependencies": { + "real-require": "^0.2.0" + } + }, + "node_modules/tmp": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", + "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/tmp-promise": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", + "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tmp": "^0.2.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toad-cache": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/toad-cache/-/toad-cache-3.7.0.tgz", + "integrity": "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "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" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/truncate-utf8-bytes": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", + "integrity": "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==", + "dev": true, + "license": "WTFPL", + "dependencies": { + "utf8-byte-length": "^1.0.1" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsx": { + "version": "4.20.6", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz", + "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type-fest": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.22.0.tgz", + "integrity": "sha512-hU/10obOIu62MGYjdskASR3CUAiYaFTtC9Pa6vHyf//mAipSvSQg6od2CnJswq7fvzNS3zJhxoRkgNVaHurWKw==", + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", + "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/utf8-byte-length": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz", + "integrity": "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==", + "dev": true, + "license": "(WTFPL OR MIT)" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/verror": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz", + "integrity": "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-plugin-solid": { + "version": "2.11.10", + "resolved": "https://registry.npmjs.org/vite-plugin-solid/-/vite-plugin-solid-2.11.10.tgz", + "integrity": "sha512-Yr1dQybmtDtDAHkii6hXuc1oVH9CPcS/Zb2jN/P36qqcrkNnVPsMTzQ06jyzFPFjj3U1IYKMVt/9ZqcwGCEbjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.23.3", + "@types/babel__core": "^7.20.4", + "babel-preset-solid": "^1.8.4", + "merge-anything": "^5.1.7", + "solid-refresh": "^0.6.3", + "vitefu": "^1.0.4" + }, + "peerDependencies": { + "@testing-library/jest-dom": "^5.16.6 || ^5.17.0 || ^6.*", + "solid-js": "^1.7.2", + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "@testing-library/jest-dom": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/vitefu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.1.tgz", + "integrity": "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==", + "dev": true, + "license": "MIT", + "workspaces": [ + "tests/deps/*", + "tests/projects/*", + "tests/projects/workspace/packages/*" + ], + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "license": "ISC" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/zip-stream": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", + "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "archiver-utils": "^3.0.4", + "compress-commons": "^4.1.2", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/zip-stream/node_modules/archiver-utils": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz", + "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "^7.2.3", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "packages/electron-app": { + "name": "@neuralnomads/codenomad-electron-app", + "version": "0.4.0", + "dependencies": { + "@codenomad/ui": "file:../ui", + "@neuralnomads/codenomad": "file:../server" + }, + "devDependencies": { + "7zip-bin": "^5.2.0", + "app-builder-bin": "^4.2.0", + "electron": "39.0.0", + "electron-builder": "^24.0.0", + "electron-vite": "4.0.1", + "png2icons": "^2.0.1", + "pngjs": "^7.0.0", + "tsx": "^4.20.6", + "typescript": "^5.3.0", + "vite": "^5.0.0", + "vite-plugin-solid": "^2.10.0" + } + }, + "packages/electron-app/node_modules/app-builder-bin": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-4.2.0.tgz", + "integrity": "sha512-PGXlkukQnroTgAaDZnnppdLzsRJmab6Rh/rJ5fKyYaYhd+FfaORH59/ArkB5dr2cAeYQU5lCeHFEwURaoBO8BA==", + "dev": true, + "license": "MIT" + }, + "packages/server": { + "name": "@neuralnomads/codenomad", + "version": "0.4.0", + "dependencies": { + "@fastify/cors": "^8.5.0", + "@fastify/reply-from": "^9.8.0", + "@fastify/static": "^7.0.4", + "commander": "^12.1.0", + "fastify": "^4.28.1", + "fuzzysort": "^2.0.4", + "pino": "^9.4.0", + "undici": "^6.19.8", + "zod": "^3.23.8" + }, + "bin": { + "codenomad": "dist/bin.js" + }, + "devDependencies": { + "cross-env": "^7.0.3", + "ts-node": "^10.9.2", + "tsx": "^4.20.6", + "typescript": "^5.6.3" + } + }, + "packages/server/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "packages/server/node_modules/fuzzysort": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/fuzzysort/-/fuzzysort-2.0.4.tgz", + "integrity": "sha512-Api1mJL+Ad7W7vnDZnWq5pGaXJjyencT+iKGia2PlHUcSsSzWwIQ3S1isiMpwpavjYtGd2FzhUIhnnhOULZgDw==", + "license": "MIT" + }, + "packages/tauri-app": { + "name": "@codenomad/tauri-app", + "version": "0.4.0", + "devDependencies": { + "@tauri-apps/cli": "^2.9.4" + } + }, + "packages/ui": { + "name": "@codenomad/ui", + "version": "0.4.0", + "dependencies": { + "@git-diff-view/solid": "^0.0.8", + "@kobalte/core": "0.13.11", + "@opencode-ai/sdk": "^1.0.138", + "@solidjs/router": "^0.13.0", + "@suid/icons-material": "^0.9.0", + "@suid/material": "^0.19.0", + "@suid/system": "^0.14.0", + "debug": "^4.4.3", + "github-markdown-css": "^5.8.1", + "lucide-solid": "^0.300.0", + "marked": "^12.0.0", + "qrcode": "^1.5.3", + "shiki": "^3.13.0", + "solid-js": "^1.8.0", + "solid-toast": "^0.5.0" + }, + "devDependencies": { + "autoprefixer": "10.4.21", + "postcss": "8.5.6", + "tailwindcss": "3", + "typescript": "^5.3.0", + "vite": "^5.0.0", + "vite-plugin-solid": "^2.10.0" + } + } + } +} diff --git a/packages/electron-app/scripts/dev.sh b/packages/electron-app/scripts/dev.sh old mode 100644 new mode 100755 diff --git a/packages/server/package.json b/packages/server/package.json index 1257f82..c6892ee 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -16,11 +16,10 @@ "codenomad": "dist/bin.js" }, "scripts": { - "build": "npm run build:ui && npm run prepare-ui && tsc -p tsconfig.json && npm run prepare-config", + "build": "npm run build:ui && npm run prepare-ui && tsc -p tsconfig.json", "build:ui": "npm run build --prefix ../ui", "prepare-ui": "node ./scripts/copy-ui-dist.mjs", - "prepare-config": "node ./scripts/copy-opencode-config.mjs", - "dev": "cross-env CODENOMAD_DEV=1 CLI_UI_DEV_SERVER=http://localhost:3000 tsx src/index.ts", + "dev": "cross-env CLI_UI_DEV_SERVER=http://localhost:3000 tsx src/index.ts", "typecheck": "tsc --noEmit -p tsconfig.json" }, "dependencies": { diff --git a/packages/server/src/server/routes/workspaces.ts b/packages/server/src/server/routes/workspaces.ts index 1541475..effc85b 100644 --- a/packages/server/src/server/routes/workspaces.ts +++ b/packages/server/src/server/routes/workspaces.ts @@ -35,16 +35,10 @@ export function registerWorkspaceRoutes(app: FastifyInstance, deps: RouteDeps) { }) app.post("/api/workspaces", async (request, reply) => { - try { - const body = WorkspaceCreateSchema.parse(request.body ?? {}) - const workspace = await deps.workspaceManager.create(body.path, body.name) - reply.code(201) - return workspace - } catch (error) { - request.log.error({ err: error }, "Failed to create workspace") - const message = error instanceof Error ? error.message : "Failed to create workspace" - reply.code(400).type("text/plain").send(message) - } + const body = WorkspaceCreateSchema.parse(request.body ?? {}) + const workspace = await deps.workspaceManager.create(body.path, body.name) + reply.code(201) + return workspace }) app.get<{ Params: { id: string } }>("/api/workspaces/:id", async (request, reply) => { diff --git a/packages/server/src/workspaces/manager.ts b/packages/server/src/workspaces/manager.ts index 02af022..404e3a1 100644 --- a/packages/server/src/workspaces/manager.ts +++ b/packages/server/src/workspaces/manager.ts @@ -1,6 +1,5 @@ import path from "path" import { spawnSync } from "child_process" -import { connect } from "net" import { EventBus } from "../events/bus" import { ConfigStore } from "../config/store" import { BinaryRegistry } from "../config/binaries" @@ -8,11 +7,8 @@ import { FileSystemBrowser } from "../filesystem/browser" import { searchWorkspaceFiles, WorkspaceFileSearchOptions } from "../filesystem/search" import { clearWorkspaceSearchCache } from "../filesystem/search-cache" import { WorkspaceDescriptor, WorkspaceFileResponse, FileSystemEntry } from "../api-types" -import { WorkspaceRuntime, ProcessExitInfo } from "./runtime" +import { WorkspaceRuntime } from "./runtime" import { Logger } from "../logger" -import { getOpencodeConfigDir } from "../opencode-config" - -const STARTUP_STABILITY_DELAY_MS = 1500 interface WorkspaceManagerOptions { rootDir: string @@ -27,11 +23,9 @@ interface WorkspaceRecord extends WorkspaceDescriptor {} export class WorkspaceManager { private readonly workspaces = new Map() private readonly runtime: WorkspaceRuntime - private readonly opencodeConfigDir: string constructor(private readonly options: WorkspaceManagerOptions) { this.runtime = new WorkspaceRuntime(this.options.eventBus, this.options.logger) - this.opencodeConfigDir = getOpencodeConfigDir() } list(): WorkspaceDescriptor[] { @@ -103,15 +97,10 @@ export class WorkspaceManager { this.options.eventBus.publish({ type: "workspace.created", workspace: descriptor }) - const preferences = this.options.configStore.get().preferences ?? {} - const userEnvironment = preferences.environmentVariables ?? {} - const environment = { - ...userEnvironment, - OPENCODE_CONFIG_DIR: this.opencodeConfigDir, - } + const environment = this.options.configStore.get().preferences.environmentVariables ?? {} try { - const { pid, port, exitPromise, getLastOutput } = await this.runtime.launch({ + const { pid, port } = await this.runtime.launch({ workspaceId: id, folder: workspacePath, binaryPath: resolvedBinaryPath, @@ -119,8 +108,6 @@ export class WorkspaceManager { onExit: (info) => this.handleProcessExit(info.workspaceId, info), }) - await this.waitForWorkspaceReadiness({ workspaceId: id, port, exitPromise, getLastOutput }) - descriptor.pid = pid descriptor.port = port descriptor.status = "ready" @@ -246,159 +233,6 @@ export class WorkspaceManager { return undefined } - private async waitForWorkspaceReadiness(params: { - workspaceId: string - port: number - exitPromise: Promise - getLastOutput: () => string - }) { - - await Promise.race([ - this.waitForPortAvailability(params.port), - params.exitPromise.then((info) => { - throw this.buildStartupError( - params.workspaceId, - "exited before becoming ready", - info, - params.getLastOutput(), - ) - }), - ]) - - await this.waitForInstanceHealth(params) - - await Promise.race([ - this.delay(STARTUP_STABILITY_DELAY_MS), - params.exitPromise.then((info) => { - throw this.buildStartupError( - params.workspaceId, - "exited shortly after start", - info, - params.getLastOutput(), - ) - }), - ]) - } - - private async waitForInstanceHealth(params: { - workspaceId: string - port: number - exitPromise: Promise - getLastOutput: () => string - }) { - const probeResult = await Promise.race([ - this.probeInstance(params.workspaceId, params.port), - params.exitPromise.then((info) => { - throw this.buildStartupError( - params.workspaceId, - "exited during health checks", - info, - params.getLastOutput(), - ) - }), - ]) - - if (probeResult.ok) { - return - } - - const latestOutput = params.getLastOutput().trim() - const outputDetails = latestOutput ? ` Last output: ${latestOutput}` : "" - const reason = probeResult.reason ?? "Health check failed" - throw new Error(`Workspace ${params.workspaceId} failed health check: ${reason}.${outputDetails}`) - } - - private async probeInstance(workspaceId: string, port: number): Promise<{ ok: boolean; reason?: string }> { - const url = `http://127.0.0.1:${port}/project/current` - - try { - const response = await fetch(url) - if (!response.ok) { - const reason = `health probe returned HTTP ${response.status}` - this.options.logger.debug({ workspaceId, status: response.status }, "Health probe returned server error") - return { ok: false, reason } - } - return { ok: true } - } catch (error) { - const reason = error instanceof Error ? error.message : String(error) - this.options.logger.debug({ workspaceId, err: error }, "Health probe failed") - return { ok: false, reason } - } - } - - private buildStartupError( - workspaceId: string, - phase: string, - exitInfo: ProcessExitInfo, - lastOutput: string, - ): Error { - const exitDetails = this.describeExit(exitInfo) - const trimmedOutput = lastOutput.trim() - const outputDetails = trimmedOutput ? ` Last output: ${trimmedOutput}` : "" - return new Error(`Workspace ${workspaceId} ${phase} (${exitDetails}).${outputDetails}`) - } - - private waitForPortAvailability(port: number, timeoutMs = 5000): Promise { - return new Promise((resolve, reject) => { - const deadline = Date.now() + timeoutMs - let settled = false - let retryTimer: NodeJS.Timeout | null = null - - const cleanup = () => { - settled = true - if (retryTimer) { - clearTimeout(retryTimer) - retryTimer = null - } - } - - const tryConnect = () => { - if (settled) { - return - } - const socket = connect({ port, host: "127.0.0.1" }, () => { - cleanup() - socket.end() - resolve() - }) - socket.once("error", () => { - socket.destroy() - if (settled) { - return - } - if (Date.now() >= deadline) { - cleanup() - reject(new Error(`Workspace port ${port} did not become ready within ${timeoutMs}ms`)) - } else { - retryTimer = setTimeout(() => { - retryTimer = null - tryConnect() - }, 100) - } - }) - } - - tryConnect() - }) - } - - private delay(durationMs: number): Promise { - if (durationMs <= 0) { - return Promise.resolve() - } - return new Promise((resolve) => setTimeout(resolve, durationMs)) - } - - private describeExit(info: ProcessExitInfo): string { - if (info.signal) { - return `signal ${info.signal}` - } - if (info.code !== null) { - return `code ${info.code}` - } - return "unknown reason" - } - private handleProcessExit(workspaceId: string, info: { code: number | null; requested: boolean }) { const workspace = this.workspaces.get(workspaceId) if (!workspace) return diff --git a/packages/server/src/workspaces/runtime.ts b/packages/server/src/workspaces/runtime.ts index 7c1c5f1..b977c11 100644 --- a/packages/server/src/workspaces/runtime.ts +++ b/packages/server/src/workspaces/runtime.ts @@ -13,7 +13,7 @@ interface LaunchOptions { onExit?: (info: ProcessExitInfo) => void } -export interface ProcessExitInfo { +interface ProcessExitInfo { workspaceId: string code: number | null signal: NodeJS.Signals | null @@ -30,18 +30,12 @@ export class WorkspaceRuntime { constructor(private readonly eventBus: EventBus, private readonly logger: Logger) {} - async launch(options: LaunchOptions): Promise<{ pid: number; port: number; exitPromise: Promise; getLastOutput: () => string }> { + async launch(options: LaunchOptions): Promise<{ pid: number; port: number }> { this.validateFolder(options.folder) const args = ["serve", "--port", "0", "--print-logs", "--log-level", "DEBUG"] const env = { ...process.env, ...(options.environment ?? {}) } - let exitResolve: ((info: ProcessExitInfo) => void) | null = null - const exitPromise = new Promise((resolveExit) => { - exitResolve = resolveExit - }) - let lastOutput = "" - return new Promise((resolve, reject) => { this.logger.info( { workspaceId: options.workspaceId, folder: options.folder, binary: options.binaryPath }, @@ -89,21 +83,11 @@ export class WorkspaceRuntime { cleanupStreams() child.removeListener("error", handleError) child.removeListener("exit", handleExit) - const exitInfo: ProcessExitInfo = { - workspaceId: options.workspaceId, - code, - signal, - requested: managed.requestedStop, - } - if (exitResolve) { - exitResolve(exitInfo) - exitResolve = null - } if (!portFound) { const reason = stderrBuffer || `Process exited with code ${code}` reject(new Error(reason)) } else { - options.onExit?.(exitInfo) + options.onExit?.({ workspaceId: options.workspaceId, code, signal, requested: managed.requestedStop }) } } @@ -112,10 +96,6 @@ export class WorkspaceRuntime { child.removeListener("exit", handleExit) this.processes.delete(options.workspaceId) this.logger.error({ workspaceId: options.workspaceId, err: error }, "Workspace runtime error") - if (exitResolve) { - exitResolve({ workspaceId: options.workspaceId, code: null, signal: null, requested: managed.requestedStop }) - exitResolve = null - } reject(error) } @@ -129,20 +109,18 @@ export class WorkspaceRuntime { stdoutBuffer = lines.pop() ?? "" for (const line of lines) { - const trimmed = line.trim() - if (!trimmed) continue - lastOutput = trimmed + if (!line.trim()) continue this.emitLog(options.workspaceId, "info", line) if (!portFound) { const portMatch = line.match(/opencode server listening on http:\/\/.+:(\d+)/i) if (portMatch) { portFound = true + cleanupStreams() child.removeListener("error", handleError) const port = parseInt(portMatch[1], 10) this.logger.info({ workspaceId: options.workspaceId, port }, "Workspace runtime allocated port") - const getLastOutput = () => lastOutput.trim() - resolve({ pid: child.pid!, port, exitPromise, getLastOutput }) + resolve({ pid: child.pid!, port }) } } } @@ -155,9 +133,7 @@ export class WorkspaceRuntime { stderrBuffer = lines.pop() ?? "" for (const line of lines) { - const trimmed = line.trim() - if (!trimmed) continue - lastOutput = `[stderr] ${trimmed}` + if (!line.trim()) continue this.emitLog(options.workspaceId, "error", line) } }) diff --git a/packages/ui/src/App.tsx b/packages/ui/src/App.tsx index 78488de..cc1b876 100644 --- a/packages/ui/src/App.tsx +++ b/packages/ui/src/App.tsx @@ -21,9 +21,11 @@ import { hasInstances, isSelectingFolder, setIsSelectingFolder, + setHasInstances, showFolderSelection, setShowFolderSelection, } from "./stores/ui" +import { instances as instanceStore } from "./stores/instances" import { useConfig } from "./stores/preferences" import { createInstance, @@ -63,12 +65,7 @@ const App: Component = () => { setThinkingBlocksExpansion, } = useConfig() const [escapeInDebounce, setEscapeInDebounce] = createSignal(false) - interface LaunchErrorState { - message: string - binaryPath: string - missingBinary: boolean - } - const [launchError, setLaunchError] = createSignal(null) + const [launchErrorBinary, setLaunchErrorBinary] = createSignal(null) const [isAdvancedSettingsOpen, setIsAdvancedSettingsOpen] = createSignal(false) const [remoteAccessOpen, setRemoteAccessOpen] = createSignal(false) const [instanceTabBarHeight, setInstanceTabBarHeight] = createSignal(0) @@ -108,30 +105,14 @@ const App: Component = () => { }) const launchErrorPath = () => { - const value = launchError()?.binaryPath + const value = launchErrorBinary() if (!value) return "opencode" return value.trim() || "opencode" } - const launchErrorMessage = () => launchError()?.message ?? "" - - const formatLaunchErrorMessage = (error: unknown): string => { - if (!error) { - return "Failed to launch workspace" - } - const raw = typeof error === "string" ? error : error instanceof Error ? error.message : String(error) - try { - const parsed = JSON.parse(raw) - if (parsed && typeof parsed.error === "string") { - return parsed.error - } - } catch { - // ignore JSON parse errors - } - return raw - } - - const isMissingBinaryMessage = (message: string): boolean => { + const isMissingBinaryError = (error: unknown): boolean => { + if (!error) return false + const message = typeof error === "string" ? error : error instanceof Error ? error.message : String(error) const normalized = message.toLowerCase() return ( normalized.includes("opencode binary not found") || @@ -142,7 +123,7 @@ const App: Component = () => { ) } - const clearLaunchError = () => setLaunchError(null) + const clearLaunchError = () => setLaunchErrorBinary(null) async function handleSelectFolder(folderPath: string, binaryPath?: string) { if (!folderPath) { @@ -154,6 +135,7 @@ const App: Component = () => { recordWorkspaceLaunch(folderPath, selectedBinary) clearLaunchError() const instanceId = await createInstance(folderPath, selectedBinary) + setHasInstances(true) setShowFolderSelection(false) setIsAdvancedSettingsOpen(false) @@ -162,13 +144,10 @@ const App: Component = () => { port: instances().get(instanceId)?.port, }) } catch (error) { - const message = formatLaunchErrorMessage(error) - const missingBinary = isMissingBinaryMessage(message) - setLaunchError({ - message, - binaryPath: selectedBinary, - missingBinary, - }) + clearLaunchError() + if (isMissingBinaryError(error)) { + setLaunchErrorBinary(selectedBinary) + } log.error("Failed to create instance", error) } finally { setIsSelectingFolder(false) @@ -212,6 +191,9 @@ const App: Component = () => { if (!confirmed) return await stopInstance(instanceId) + if (instances().size === 0) { + setHasInstances(false) + } } async function handleNewSession(instanceId: string) { @@ -322,7 +304,7 @@ const App: Component = () => { onClose={handleDisconnectedInstanceClose} /> - +
@@ -330,8 +312,8 @@ const App: Component = () => {
Unable to launch OpenCode - We couldn't start the selected OpenCode binary. Review the error output below or choose a different - binary from Advanced Settings. + Install the OpenCode CLI and make sure it is available in your PATH, or pick a custom binary from + Advanced Settings.
@@ -340,23 +322,10 @@ const App: Component = () => {

{launchErrorPath()}

- -
-

Error output

-
{launchErrorMessage()}
-
-
-
- - - + diff --git a/packages/ui/src/lib/logger.ts b/packages/ui/src/lib/logger.ts index 68d8fc0..dd3617e 100644 --- a/packages/ui/src/lib/logger.ts +++ b/packages/ui/src/lib/logger.ts @@ -1,6 +1,6 @@ import debug from "debug" -export type LoggerNamespace = "sse" | "api" | "session" | "actions" | "solo" | "multix-chat" +export type LoggerNamespace = "sse" | "api" | "session" | "actions" interface Logger { log: (...args: unknown[]) => void @@ -22,7 +22,7 @@ export interface LoggerControls { disableAllLoggers: () => void } -const KNOWN_NAMESPACES: LoggerNamespace[] = ["sse", "api", "session", "actions", "solo", "multix-chat"] +const KNOWN_NAMESPACES: LoggerNamespace[] = ["sse", "api", "session", "actions"] const STORAGE_KEY = "opencode:logger:namespaces" const namespaceLoggers = new Map() diff --git a/packages/ui/src/stores/instances.ts b/packages/ui/src/stores/instances.ts index dbce02b..0d10adb 100644 --- a/packages/ui/src/stores/instances.ts +++ b/packages/ui/src/stores/instances.ts @@ -34,11 +34,6 @@ const [logStreamingState, setLogStreamingState] = createSignal>(new Map()) const [activePermissionId, setActivePermissionId] = createSignal>(new Map()) const permissionSessionCounts = new Map>() - -function syncHasInstancesFlag() { - const readyExists = Array.from(instances().values()).some((instance) => instance.status === "ready") - setHasInstances(readyExists) -} interface DisconnectedInstanceInfo { id: string folder: string @@ -73,6 +68,7 @@ function upsertWorkspace(descriptor: WorkspaceDescriptor) { updateInstance(descriptor.id, mapped) } else { addInstance(mapped) + setHasInstances(true) } if (descriptor.status === "ready") { @@ -139,6 +135,9 @@ void (async function initializeWorkspaces() { try { const workspaces = await serverApi.fetchWorkspaces() workspaces.forEach((workspace) => upsertWorkspace(workspace)) + if (workspaces.length === 0) { + setHasInstances(false) + } } catch (error) { log.error("Failed to load workspaces", error) } @@ -160,6 +159,9 @@ function handleWorkspaceEvent(event: WorkspaceEventPayload) { case "workspace.stopped": releaseInstanceResources(event.workspaceId) removeInstance(event.workspaceId) + if (instances().size === 0) { + setHasInstances(false) + } break case "workspace.log": handleWorkspaceLog(event.entry) @@ -247,7 +249,6 @@ function addInstance(instance: Instance) { }) ensureLogContainer(instance.id) ensureLogStreamingState(instance.id) - syncHasInstancesFlag() } function updateInstance(id: string, updates: Partial) { @@ -259,7 +260,6 @@ function updateInstance(id: string, updates: Partial) { } return next }) - syncHasInstancesFlag() } function removeInstance(id: string) { @@ -301,7 +301,6 @@ function removeInstance(id: string) { clearCacheForInstance(id) messageStoreBus.unregisterInstance(id) clearInstanceDraftPrompts(id) - syncHasInstancesFlag() } async function createInstance(folder: string, _binaryPath?: string): Promise { @@ -329,6 +328,9 @@ async function stopInstance(id: string) { } removeInstance(id) + if (instances().size === 0) { + setHasInstances(false) + } } async function fetchLspStatus(instanceId: string): Promise { @@ -588,6 +590,9 @@ async function acknowledgeDisconnectedInstance(): Promise { log.error("Failed to stop disconnected instance", error) } finally { setDisconnectedInstance(null) + if (instances().size === 0) { + setHasInstances(false) + } } } diff --git a/tasks/README.md b/tasks/README.md new file mode 100644 index 0000000..285a1c8 --- /dev/null +++ b/tasks/README.md @@ -0,0 +1,177 @@ +# Task Management + +This directory contains the task breakdown for building CodeNomad. + +## Structure + +- `todo/` - Tasks waiting to be worked on +- `done/` - Completed tasks (moved from todo/) + +## Task Naming Convention + +Tasks are numbered sequentially with a descriptive name: + +``` +001-project-setup.md +002-empty-state-ui.md +003-process-manager.md +... +``` + +## Task Format + +Each task file contains: + +1. **Goal** - What this task achieves +2. **Prerequisites** - What must be done first +3. **Acceptance Criteria** - Checklist of requirements +4. **Steps** - Detailed implementation guide +5. **Testing Checklist** - How to verify completion +6. **Dependencies** - What blocks/is blocked by this task +7. **Estimated Time** - Rough time estimate +8. **Notes** - Additional context + +## Workflow + +### Starting a Task + +1. Read the task file thoroughly +2. Ensure prerequisites are met +3. Check dependencies are complete +4. Create a feature branch: `feature/task-XXX-name` + +### Working on a Task + +1. Follow steps in order +2. Check off acceptance criteria as you complete them +3. Run tests frequently +4. Commit regularly with descriptive messages + +### Completing a Task + +1. Verify all acceptance criteria met +2. Run full testing checklist +3. Update task file with any notes/changes +4. Move task from `todo/` to `done/` +5. Create PR for review + +## Current Tasks + +### Phase 1: Foundation (Tasks 001-005) + +- [x] 001 - Project Setup +- [x] 002 - Empty State UI +- [x] 003 - Process Manager +- [x] 004 - SDK Integration +- [x] 005 - Session Picker Modal + +### Phase 2: Core Chat (Tasks 006-010) + +- [x] 006 - Instance & Session Tabs +- [x] 007 - Message Display +- [x] 008 - SSE Integration +- [x] 009 - Prompt Input (Basic) +- [x] 010 - Tool Call Rendering + +### Phase 3: Essential Features (Tasks 011-015) + +- [x] 011 - Agent/Model Selectors +- [x] 012 - Markdown Rendering +- [x] 013 - Logs Tab +- [ ] 014 - Error Handling +- [ ] 015 - Keyboard Shortcuts + +### Phase 4: Multi-Instance (Tasks 016-020) + +- [ ] 016 - Instance Tabs +- [ ] 017 - Instance Persistence +- [ ] 018 - Child Session Handling +- [ ] 019 - Instance Lifecycle +- [ ] 020 - Multiple SDK Clients + +### Phase 5: Advanced Input (Tasks 021-025) + +- [ ] 021 - Slash Commands +- [ ] 022 - File Attachments +- [ ] 023 - Drag & Drop +- [ ] 024 - Attachment Chips +- [ ] 025 - Input History + +### Phase 6: Polish (Tasks 026-030) + +- [ ] 026 - Message Actions +- [ ] 027 - Search in Session +- [ ] 028 - Session Management +- [ ] 029 - Settings UI +- [ ] 030 - Native Menus + +### Phase 7: System Integration (Tasks 031-035) + +- [ ] 031 - System Tray +- [ ] 032 - Notifications +- [ ] 033 - Auto-updater +- [ ] 034 - Crash Reporting +- [ ] 035 - Performance Profiling + +### Phase 8: Advanced (Tasks 036-040) + +- [ ] 036 - Virtual Scrolling +- [ ] 037 - Advanced Search +- [ ] 038 - Workspace Management +- [ ] 039 - Theme Customization +- [ ] 040 - Plugin System + +## Priority Levels + +Tasks are prioritized as follows: + +- **P0 (MVP)**: Must have for first release (Tasks 001-015) +- **P1 (Beta)**: Important for beta (Tasks 016-030) +- **P2 (v1.0)**: Should have for v1.0 (Tasks 031-035) +- **P3 (Future)**: Nice to have (Tasks 036-040) + +## Dependencies Graph + +``` +001 (Setup) + ├─ 002 (Empty State) + │ └─ 003 (Process Manager) + │ └─ 004 (SDK Integration) + │ └─ 005 (Session Picker) + │ ├─ 006 (Tabs) + │ │ └─ 007 (Messages) + │ │ └─ 008 (SSE) + │ │ └─ 009 (Input) + │ │ └─ 010 (Tool Calls) + │ │ └─ 011-015 (Essential Features) + │ │ └─ 016-020 (Multi-Instance) + │ │ └─ 021-025 (Advanced Input) + │ │ └─ 026-030 (Polish) + │ │ └─ 031-035 (System) + │ │ └─ 036-040 (Advanced) +``` + +## Tips + +- **Don't skip steps** - They're ordered for a reason +- **Test as you go** - Don't wait until the end +- **Keep tasks small** - Break down if >1 day of work +- **Document issues** - Note any blockers or problems +- **Ask questions** - If unclear, ask before proceeding + +## Tracking Progress + +Update this file as tasks complete: + +- Change `[ ]` to `[x]` in the task list +- Move completed task files to `done/` +- Update build roadmap doc + +## Getting Help + +If stuck on a task: + +1. Review prerequisites and dependencies +2. Check related documentation in `docs/` +3. Review similar patterns in existing code +4. Ask for clarification on unclear requirements diff --git a/tasks/done/001-project-setup.md b/tasks/done/001-project-setup.md new file mode 100644 index 0000000..fe55dc4 --- /dev/null +++ b/tasks/done/001-project-setup.md @@ -0,0 +1,262 @@ +# Task 001: Project Setup & Boilerplate + +## Goal + +Set up the basic Electron + SolidJS + Vite project structure with all necessary dependencies and configuration files. + +## Prerequisites + +- Node.js 18+ installed +- Bun package manager +- OpenCode CLI installed and accessible in PATH + +## Acceptance Criteria + +- [ ] Project structure matches documented layout +- [ ] All dependencies installed +- [ ] Dev server starts successfully +- [ ] Electron window launches +- [ ] Hot reload works for renderer +- [ ] TypeScript compilation works +- [ ] Basic "Hello World" renders + +## Steps + +### 1. Initialize Package + +- Create `package.json` with project metadata +- Set `name`: `@opencode-ai/client` +- Set `version`: `0.1.0` +- Set `type`: `module` +- Set `main`: `dist/main/main.js` + +### 2. Install Core Dependencies + +**Production:** + +- `electron` ^28.0.0 +- `solid-js` ^1.8.0 +- `@solidjs/router` ^0.13.0 +- `@opencode-ai/sdk` (from workspace) + +**Development:** + +- `electron-vite` ^2.0.0 +- `electron-builder` ^24.0.0 +- `vite` ^5.0.0 +- `vite-plugin-solid` ^2.10.0 +- `typescript` ^5.3.0 +- `tailwindcss` ^4.0.0 +- `@tailwindcss/vite` ^4.0.0 + +**UI Libraries:** + +- `@kobalte/core` ^0.13.0 +- `shiki` ^1.0.0 +- `marked` ^12.0.0 +- `lucide-solid` ^0.300.0 + +### 3. Create Directory Structure + +``` +packages/opencode-client/ +├── electron/ +│ ├── main/ +│ │ └── main.ts +│ ├── preload/ +│ │ └── index.ts +│ └── resources/ +│ └── icon.png +├── src/ +│ ├── components/ +│ ├── stores/ +│ ├── lib/ +│ ├── hooks/ +│ ├── types/ +│ ├── App.tsx +│ ├── main.tsx +│ └── index.css +├── docs/ +├── tasks/ +│ ├── todo/ +│ └── done/ +├── package.json +├── tsconfig.json +├── tsconfig.node.json +├── electron.vite.config.ts +├── tailwind.config.js +├── .gitignore +└── README.md +``` + +### 4. Configure TypeScript + +**tsconfig.json** (for renderer): + +- `target`: ES2020 +- `module`: ESNext +- `jsx`: preserve +- `jsxImportSource`: solid-js +- `moduleResolution`: bundler +- `strict`: true +- Path alias: `@/*` → `./src/*` + +**tsconfig.node.json** (for main & preload): + +- `target`: ES2020 +- `module`: ESNext +- `moduleResolution`: bundler +- Include: `electron/**/*.ts` + +### 5. Configure Electron Vite + +**electron.vite.config.ts:** + +- Main process config: External electron +- Preload config: External electron +- Renderer config: + - SolidJS plugin + - TailwindCSS plugin + - Path alias resolution + - Dev server port: 3000 + +### 6. Configure TailwindCSS + +**tailwind.config.js:** + +- Content: `['./src/**/*.{ts,tsx}']` +- Theme: Default (will customize later) +- Plugins: None initially + +**src/index.css:** + +```css +@import "tailwindcss"; +``` + +### 7. Create Main Process Entry + +**electron/main/main.ts:** + +- Import app, BrowserWindow from electron +- Set up window creation +- Window size: 1400x900 +- Min size: 800x600 +- Web preferences: + - preload: path to preload script + - contextIsolation: true + - nodeIntegration: false +- Load URL based on environment: + - Dev: http://localhost:3000 + - Prod: Load dist/index.html +- Handle app lifecycle: + - ready event + - window-all-closed (quit on non-macOS) + - activate (recreate window on macOS) + +### 8. Create Preload Script + +**electron/preload/index.ts:** + +- Import contextBridge, ipcRenderer +- Expose electronAPI object: + - Placeholder methods for future IPC +- Type definitions for window.electronAPI + +### 9. Create Renderer Entry + +**src/main.tsx:** + +- Import render from solid-js/web +- Import App component +- Render to #root element + +**src/App.tsx:** + +- Basic component with "Hello CodeNomad" +- Display environment info +- Basic styling with TailwindCSS + +**index.html:** + +- Root div with id="root" +- Link to src/main.tsx + +### 10. Add Scripts to package.json + +```json +{ + "scripts": { + "dev": "electron-vite dev", + "build": "electron-vite build", + "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.node.json", + "preview": "electron-vite preview", + "package:mac": "electron-builder --mac", + "package:win": "electron-builder --win", + "package:linux": "electron-builder --linux" + } +} +``` + +### 11. Configure Electron Builder + +**electron-builder.yml** or in package.json: + +- appId: ai.opencode.client +- Product name: CodeNomad +- Build resources: electron/resources +- Files to include: dist/, package.json +- Directories: + - output: release + - buildResources: electron/resources +- Platform-specific configs (basic) + +### 12. Add .gitignore + +``` +node_modules/ +dist/ +release/ +.DS_Store +*.log +.vite/ +.electron-vite/ +``` + +### 13. Create README + +- Project description +- Prerequisites +- Installation instructions +- Development commands +- Build commands +- Architecture overview link + +## Verification Steps + +1. Run `bun install` +2. Run `bun run dev` +3. Verify Electron window opens +4. Verify "Hello CodeNomad" displays +5. Make a change to App.tsx +6. Verify hot reload updates UI +7. Run `bun run typecheck` +8. Verify no TypeScript errors +9. Run `bun run build` +10. Verify dist/ folder created + +## Dependencies for Next Tasks + +- Task 002 (Empty State) depends on this +- Task 003 (Process Manager) depends on this + +## Estimated Time + +2-3 hours + +## Notes + +- Keep this minimal - just the skeleton +- Don't add any business logic yet +- Focus on getting build pipeline working +- Use official Electron + Vite + Solid templates as reference diff --git a/tasks/done/002-empty-state-ui.md b/tasks/done/002-empty-state-ui.md new file mode 100644 index 0000000..4ef9563 --- /dev/null +++ b/tasks/done/002-empty-state-ui.md @@ -0,0 +1,280 @@ +# Task 002: Empty State UI & Folder Selection + +## Goal + +Create the initial empty state interface that appears when no instances are running, with folder selection capability. + +## Prerequisites + +- Task 001 completed (project setup) +- Basic understanding of SolidJS components +- Electron IPC understanding + +## Acceptance Criteria + +- [ ] Empty state displays when no instances exist +- [ ] "Select Folder" button visible and styled +- [ ] Clicking button triggers Electron dialog +- [ ] Selected folder path displays temporarily +- [ ] UI matches design spec (centered, clean) +- [ ] Keyboard shortcut Cmd/Ctrl+N works +- [ ] Error handling for cancelled selection + +## Steps + +### 1. Create Empty State Component + +**src/components/empty-state.tsx:** + +**Structure:** + +- Centered container +- Large folder icon (from lucide-solid) +- Subheading: "Select a folder to start coding with AI" +- Primary button: "Select Folder" +- Helper text: "Keyboard shortcut: Cmd/Ctrl+N" + +**Styling:** + +- Use TailwindCSS utilities +- Center vertically and horizontally +- Max width: 500px +- Padding: 32px +- Icon size: 64px +- Text sizes: Heading 24px, body 16px, helper 14px +- Colors: Follow design spec (light/dark mode) + +**Props:** + +- `onSelectFolder: () => void` - Callback when button clicked + +### 2. Create UI Store + +**src/stores/ui.ts:** + +**State:** + +```typescript +interface UIStore { + hasInstances: boolean + selectedFolder: string | null + isSelectingFolder: boolean +} +``` + +**Signals:** + +- `hasInstances` - Reactive boolean +- `selectedFolder` - Reactive string or null +- `isSelectingFolder` - Reactive boolean (loading state) + +**Actions:** + +- `setHasInstances(value: boolean)` +- `setSelectedFolder(path: string | null)` +- `setIsSelectingFolder(value: boolean)` + +### 3. Implement IPC for Folder Selection + +**electron/main/main.ts additions:** + +**IPC Handler:** + +- Register handler for 'dialog:selectFolder' +- Use `dialog.showOpenDialog()` with: + - `properties: ['openDirectory']` + - Title: "Select Project Folder" + - Button label: "Select" +- Return selected folder path or null if cancelled +- Handle errors gracefully + +**electron/preload/index.ts additions:** + +**Expose method:** + +```typescript +electronAPI: { + selectFolder: () => Promise +} +``` + +**Type definitions:** + +```typescript +interface ElectronAPI { + selectFolder: () => Promise +} + +declare global { + interface Window { + electronAPI: ElectronAPI + } +} +``` + +### 4. Update App Component + +**src/App.tsx:** + +**Logic:** + +- Import UI store +- Import EmptyState component +- Check if `hasInstances` is false +- If false, render EmptyState +- If true, render placeholder for instance UI (future) + +**Folder selection handler:** + +```typescript +async function handleSelectFolder() { + setIsSelectingFolder(true) + try { + const folder = await window.electronAPI.selectFolder() + if (folder) { + setSelectedFolder(folder) + // TODO: Will trigger instance creation in Task 003 + console.log("Selected folder:", folder) + } + } catch (error) { + console.error("Folder selection failed:", error) + // TODO: Show error toast (Task 010) + } finally { + setIsSelectingFolder(false) + } +} +``` + +### 5. Add Keyboard Shortcut + +**electron/main/menu.ts (new file):** + +**Create application menu:** + +- File menu: + - New Instance (Cmd/Ctrl+N) + - Click: Send 'menu:newInstance' to renderer + - Separator + - Quit (Cmd/Ctrl+Q) + +**Platform-specific menu:** + +- macOS: Include app menu with About, Hide, etc. +- Windows/Linux: Standard File menu + +**Register menu in main.ts:** + +- Import Menu, buildFromTemplate +- Create menu structure +- Set as application menu + +**electron/preload/index.ts additions:** + +```typescript +electronAPI: { + onNewInstance: (callback: () => void) => void +} +``` + +**src/App.tsx additions:** + +- Listen for 'newInstance' event +- Trigger handleSelectFolder when received + +### 6. Add Loading State + +**Button states:** + +- Default: "Select Folder" +- Loading: "Selecting..." with spinner icon +- Disabled when isSelectingFolder is true + +**Spinner component:** + +- Use lucide-solid Loader2 icon +- Add spin animation class +- Size: 16px + +### 7. Add Validation + +**Folder validation (in handler):** + +- Check if folder exists +- Check if readable +- Check if it's actually a directory +- Show appropriate error if invalid + +**Error messages:** + +- "Folder does not exist" +- "Cannot access folder (permission denied)" +- "Please select a directory, not a file" + +### 8. Style Refinements + +**Responsive behavior:** + +- Works at minimum window size (800x600) +- Maintains centering +- Text remains readable + +**Accessibility:** + +- Button has proper ARIA labels +- Keyboard focus visible +- Screen reader friendly text + +**Theme support:** + +- Test in light mode +- Test in dark mode (use prefers-color-scheme) +- Icons and text have proper contrast + +### 9. Add Helpful Context + +**Additional helper text:** + +- "Examples: ~/projects/my-app" +- "You can have multiple instances of the same folder" + +**Icon improvements:** + +- Use animated folder icon (optional) +- Add subtle entrance animation (fade in) + +## Testing Checklist + +**Manual Tests:** + +1. Launch app → Empty state appears +2. Click "Select Folder" → Dialog opens +3. Select folder → Path logged to console +4. Cancel dialog → No error, back to empty state +5. Press Cmd/Ctrl+N → Dialog opens +6. Select non-directory → Error shown +7. Select restricted folder → Permission error shown +8. Resize window → Layout stays centered + +**Edge Cases:** + +- Very long folder paths (ellipsis) +- Special characters in folder name +- Folder on network drive +- Folder that gets deleted while selected + +## Dependencies + +- **Blocks:** Task 003 (needs folder path to create instance) +- **Blocked by:** Task 001 (needs project setup) + +## Estimated Time + +2-3 hours + +## Notes + +- Keep UI simple and clean +- Focus on UX - clear messaging +- Don't implement instance creation yet (that's Task 003) +- Log selected folder to console for verification +- Prepare for state management patterns used in later tasks diff --git a/tasks/done/003-process-manager.md b/tasks/done/003-process-manager.md new file mode 100644 index 0000000..c2671df --- /dev/null +++ b/tasks/done/003-process-manager.md @@ -0,0 +1,430 @@ +# Task 003: OpenCode Server Process Management + +## Goal + +Implement the ability to spawn, manage, and kill OpenCode server processes from the Electron main process. + +## Prerequisites + +- Task 001 completed (project setup) +- Task 002 completed (folder selection working) +- OpenCode CLI installed and in PATH +- Understanding of Node.js child_process API + +## Acceptance Criteria + +- [ ] Can spawn `opencode serve` for a folder +- [ ] Parses stdout to extract port number +- [ ] Returns port and PID to renderer +- [ ] Handles spawn errors gracefully +- [ ] Can kill process on command +- [ ] Captures and forwards stdout/stderr +- [ ] Timeout protection (10 seconds) +- [ ] Process cleanup on app quit + +## Steps + +### 1. Create Process Manager Module + +**electron/main/process-manager.ts:** + +**Exports:** + +```typescript +interface ProcessInfo { + pid: number + port: number +} + +interface ProcessManager { + spawn(folder: string): Promise + kill(pid: number): Promise + getStatus(pid: number): "running" | "stopped" | "unknown" + getAllProcesses(): Map +} + +interface ProcessMeta { + pid: number + port: number + folder: string + startTime: number + childProcess: ChildProcess +} +``` + +### 2. Implement Spawn Logic + +**spawn(folder: string):** + +**Pre-flight checks:** + +- Verify `opencode` binary exists in PATH + - Use `which opencode` or `where opencode` + - If not found, reject with helpful error +- Verify folder exists and is directory + - Use `fs.stat()` to check + - If invalid, reject with error +- Verify folder is readable + - Check permissions + - If denied, reject with error + +**Process spawning:** + +- Use `child_process.spawn()` +- Command: `opencode` +- Args: `['serve', '--port', '0']` + - Port 0 = random available port +- Options: + - `cwd`: The selected folder + - `stdio`: `['ignore', 'pipe', 'pipe']` + - stdin: ignore + - stdout: pipe (we'll read it) + - stderr: pipe (for errors) + - `env`: Inherit process.env + - `shell`: false (security) + +**Port extraction:** + +- Listen to stdout data events +- Buffer output line by line +- Regex match: `/Server listening on port (\d+)/` or similar +- Extract port number when found +- Store process metadata +- Resolve promise with { pid, port } + +**Timeout handling:** + +- Set 10 second timeout +- If port not found within timeout: + - Kill the process + - Reject promise with timeout error +- Clear timeout once port found + +**Error handling:** + +- Listen to process 'error' event + - Common: ENOENT (binary not found) + - Reject promise immediately +- Listen to process 'exit' event + - If exits before port found: + - Read stderr buffer + - Reject with exit code and stderr + +### 3. Implement Kill Logic + +**kill(pid: number):** + +**Find process:** + +- Look up pid in internal Map +- If not found, reject with "Process not found" + +**Graceful shutdown:** + +- Send SIGTERM signal first +- Wait 2 seconds +- If still running, send SIGKILL +- Remove from internal Map +- Resolve when process exits + +**Cleanup:** + +- Close stdio streams +- Remove all event listeners +- Free resources + +### 4. Implement Status Check + +**getStatus(pid: number):** + +**Check if running:** + +- On Unix: Use `process.kill(pid, 0)` + - Returns true if running + - Throws if not running +- On Windows: Use tasklist or similar +- Return 'running', 'stopped', or 'unknown' + +### 5. Add Process Tracking + +**Internal state:** + +```typescript +const processes = new Map() +``` + +**Track all spawned processes:** + +- Add on successful spawn +- Remove on kill or exit +- Use for cleanup on app quit + +### 6. Implement Auto-cleanup + +**On app quit:** + +- Listen to app 'before-quit' event +- Kill all tracked processes +- Wait for all to exit (with timeout) +- Prevent quit until cleanup done + +**On process crash:** + +- Listen to process 'exit' event +- If unexpected exit: + - Log error + - Notify renderer via IPC + - Remove from tracking + +### 7. Add Logging + +**Log output forwarding:** + +- Listen to stdout/stderr +- Parse into lines +- Send to renderer via IPC events + - Event: 'instance:log' + - Payload: { pid, level: 'info' | 'error', message } + +**Log important events:** + +- Process spawned +- Port discovered +- Process exited +- Errors occurred + +### 8. Add IPC Handlers + +**electron/main/ipc.ts (new file):** + +**Register handlers:** + +```typescript +ipcMain.handle("process:spawn", async (event, folder: string) => { + return await processManager.spawn(folder) +}) + +ipcMain.handle("process:kill", async (event, pid: number) => { + return await processManager.kill(pid) +}) + +ipcMain.handle("process:status", async (event, pid: number) => { + return processManager.getStatus(pid) +}) +``` + +**Send events:** + +```typescript +// When process exits unexpectedly +webContents.send("process:exited", { pid, code, signal }) + +// When log output received +webContents.send("process:log", { pid, level, message }) +``` + +### 9. Update Preload Script + +**electron/preload/index.ts additions:** + +**Expose methods:** + +```typescript +electronAPI: { + spawnServer: (folder: string) => Promise<{ pid: number, port: number }> + killServer: (pid: number) => Promise + getServerStatus: (pid: number) => Promise + + onServerExited: (callback: (data: any) => void) => void + onServerLog: (callback: (data: any) => void) => void +} +``` + +**Type definitions:** + +```typescript +interface ProcessInfo { + pid: number + port: number +} + +interface ElectronAPI { + // ... previous methods + spawnServer: (folder: string) => Promise + killServer: (pid: number) => Promise + getServerStatus: (pid: number) => Promise<"running" | "stopped" | "unknown"> + onServerExited: (callback: (data: { pid: number; code: number }) => void) => void + onServerLog: (callback: (data: { pid: number; level: string; message: string }) => void) => void +} +``` + +### 10. Create Instance Store + +**src/stores/instances.ts:** + +**State:** + +```typescript +interface Instance { + id: string // UUID + folder: string + port: number + pid: number + status: "starting" | "ready" | "error" | "stopped" + error?: string +} + +interface InstanceStore { + instances: Map + activeInstanceId: string | null +} +``` + +**Actions:** + +```typescript +async function createInstance(folder: string) { + const id = generateId() + + // Add with 'starting' status + instances.set(id, { + id, + folder, + port: 0, + pid: 0, + status: "starting", + }) + + try { + // Spawn server + const { pid, port } = await window.electronAPI.spawnServer(folder) + + // Update with port and pid + instances.set(id, { + ...instances.get(id)!, + port, + pid, + status: "ready", + }) + + return id + } catch (error) { + // Update with error + instances.set(id, { + ...instances.get(id)!, + status: "error", + error: error.message, + }) + throw error + } +} + +async function removeInstance(id: string) { + const instance = instances.get(id) + if (!instance) return + + // Kill server + if (instance.pid) { + await window.electronAPI.killServer(instance.pid) + } + + // Remove from store + instances.delete(id) + + // If was active, clear active + if (activeInstanceId === id) { + activeInstanceId = null + } +} +``` + +### 11. Wire Up Folder Selection + +**src/App.tsx updates:** + +**After folder selected:** + +```typescript +async function handleSelectFolder() { + const folder = await window.electronAPI.selectFolder() + if (!folder) return + + try { + const instanceId = await createInstance(folder) + setActiveInstance(instanceId) + + // Hide empty state, show instance UI + setHasInstances(true) + } catch (error) { + console.error("Failed to create instance:", error) + // TODO: Show error toast + } +} +``` + +**Listen for process exit:** + +```typescript +onMount(() => { + window.electronAPI.onServerExited(({ pid }) => { + // Find instance by PID + const instance = Array.from(instances.values()).find((i) => i.pid === pid) + + if (instance) { + // Update status + instances.set(instance.id, { + ...instance, + status: "stopped", + }) + + // TODO: Show notification (Task 010) + } + }) +}) +``` + +## Testing Checklist + +**Manual Tests:** + +1. Select folder → Server spawns +2. Console shows "Spawned PID: XXX, Port: YYYY" +3. Check `ps aux | grep opencode` → Process running +4. Quit app → Process killed +5. Select invalid folder → Error shown +6. Select without opencode installed → Helpful error +7. Spawn multiple instances → All tracked +8. Kill one instance → Others continue running + +**Error Cases:** + +- opencode not in PATH +- Permission denied on folder +- Port already in use (should not happen with port 0) +- Server crashes immediately +- Timeout (server takes >10s to start) + +**Edge Cases:** + +- Very long folder path +- Folder with spaces in name +- Folder on network drive (slow to spawn) +- Multiple instances same folder (different ports) + +## Dependencies + +- **Blocks:** Task 004 (needs running server to connect SDK) +- **Blocked by:** Task 001, Task 002 + +## Estimated Time + +4-5 hours + +## Notes + +- Security: Never use shell execution with user input +- Cross-platform: Test on macOS, Windows, Linux +- Error messages must be actionable +- Log everything for debugging +- Consider rate limiting (max 10 instances?) +- Memory: Track process memory usage (future enhancement) diff --git a/tasks/done/004-sdk-integration.md b/tasks/done/004-sdk-integration.md new file mode 100644 index 0000000..0ac579f --- /dev/null +++ b/tasks/done/004-sdk-integration.md @@ -0,0 +1,504 @@ +# Task 004: SDK Client Integration & Session Management + +## Goal + +Integrate the OpenCode SDK to communicate with running servers, fetch session lists, and manage session lifecycle. + +## Prerequisites + +- Task 003 completed (server spawning works) +- OpenCode SDK package available +- Understanding of HTTP/REST APIs +- Understanding of SolidJS reactivity + +## Acceptance Criteria + +- [ ] SDK client created per instance +- [ ] Can fetch session list from server +- [ ] Can create new session +- [ ] Can get session details +- [ ] Can delete session +- [ ] Client lifecycle tied to instance lifecycle +- [ ] Error handling for network failures +- [ ] Proper TypeScript types throughout + +## Steps + +### 1. Create SDK Manager Module + +**src/lib/sdk-manager.ts:** + +**Purpose:** + +- Manage SDK client instances +- One client per server (per port) +- Create, retrieve, destroy clients + +**Interface:** + +```typescript +interface SDKManager { + createClient(port: number): OpenCodeClient + getClient(port: number): OpenCodeClient | null + destroyClient(port: number): void + destroyAll(): void +} +``` + +**Implementation details:** + +- Store clients in Map +- Create client with base URL: `http://localhost:${port}` +- Handle client creation errors +- Clean up on destroy + +### 2. Update Instance Store + +**src/stores/instances.ts additions:** + +**Add client to Instance:** + +```typescript +interface Instance { + // ... existing fields + client: OpenCodeClient | null +} +``` + +**Update createInstance:** + +- After server spawns successfully +- Create SDK client for that port +- Store in instance.client +- Handle client creation errors + +**Update removeInstance:** + +- Destroy SDK client before removing +- Call sdkManager.destroyClient(port) + +### 3. Create Session Store + +**src/stores/sessions.ts:** + +**State structure:** + +```typescript +interface Session { + id: string + instanceId: string + title: string + parentId: string | null + agent: string + model: { + providerId: string + modelId: string + } + time: { + created: number + updated: number + } +} + +interface SessionStore { + // Sessions grouped by instance + sessions: Map> + + // Active session per instance + activeSessionId: Map +} +``` + +**Core actions:** + +```typescript +// Fetch all sessions for an instance +async function fetchSessions(instanceId: string): Promise + +// Create new session +async function createSession(instanceId: string, agent: string): Promise + +// Delete session +async function deleteSession(instanceId: string, sessionId: string): Promise + +// Set active session +function setActiveSession(instanceId: string, sessionId: string): void + +// Get active session +function getActiveSession(instanceId: string): Session | null + +// Get all sessions for instance +function getSessions(instanceId: string): Session[] +``` + +### 4. Implement Session Fetching + +**fetchSessions implementation:** + +```typescript +async function fetchSessions(instanceId: string) { + const instance = instances.get(instanceId) + if (!instance || !instance.client) { + throw new Error("Instance not ready") + } + + try { + const response = await instance.client.session.list() + + // Convert API response to Session objects + const sessionMap = new Map() + + for (const apiSession of response.data) { + sessionMap.set(apiSession.id, { + id: apiSession.id, + instanceId, + title: apiSession.title || "Untitled", + parentId: apiSession.parentId || null, + agent: "", // Will be populated from messages + model: { providerId: "", modelId: "" }, + time: { + created: apiSession.time.created, + updated: apiSession.time.updated, + }, + }) + } + + sessions.set(instanceId, sessionMap) + } catch (error) { + console.error("Failed to fetch sessions:", error) + throw error + } +} +``` + +### 5. Implement Session Creation + +**createSession implementation:** + +```typescript +async function createSession(instanceId: string, agent: string): Promise { + const instance = instances.get(instanceId) + if (!instance || !instance.client) { + throw new Error("Instance not ready") + } + + try { + const response = await instance.client.session.create({ + // OpenCode API might need specific params + }) + + const session: Session = { + id: response.data.id, + instanceId, + title: "New Session", + parentId: null, + agent, + model: { providerId: "", modelId: "" }, + time: { + created: Date.now(), + updated: Date.now(), + }, + } + + // Add to store + const instanceSessions = sessions.get(instanceId) || new Map() + instanceSessions.set(session.id, session) + sessions.set(instanceId, instanceSessions) + + return session + } catch (error) { + console.error("Failed to create session:", error) + throw error + } +} +``` + +### 6. Implement Session Deletion + +**deleteSession implementation:** + +```typescript +async function deleteSession(instanceId: string, sessionId: string): Promise { + const instance = instances.get(instanceId) + if (!instance || !instance.client) { + throw new Error("Instance not ready") + } + + try { + await instance.client.session.delete({ path: { id: sessionId } }) + + // Remove from store + const instanceSessions = sessions.get(instanceId) + if (instanceSessions) { + instanceSessions.delete(sessionId) + } + + // Clear active if it was active + if (activeSessionId.get(instanceId) === sessionId) { + activeSessionId.delete(instanceId) + } + } catch (error) { + console.error("Failed to delete session:", error) + throw error + } +} +``` + +### 7. Implement Agent & Model Fetching + +**Fetch available agents:** + +```typescript +interface Agent { + name: string + description: string + mode: string +} + +async function fetchAgents(instanceId: string): Promise { + const instance = instances.get(instanceId) + if (!instance || !instance.client) { + throw new Error("Instance not ready") + } + + try { + const response = await instance.client.agent.list() + return response.data.filter((agent) => agent.mode !== "subagent") + } catch (error) { + console.error("Failed to fetch agents:", error) + return [] + } +} +``` + +**Fetch available models:** + +```typescript +interface Provider { + id: string + name: string + models: Model[] +} + +interface Model { + id: string + name: string + providerId: string +} + +async function fetchProviders(instanceId: string): Promise { + const instance = instances.get(instanceId) + if (!instance || !instance.client) { + throw new Error("Instance not ready") + } + + try { + const response = await instance.client.config.providers() + return response.data.providers.map((provider) => ({ + id: provider.id, + name: provider.name, + models: Object.entries(provider.models).map(([id, model]) => ({ + id, + name: model.name, + providerId: provider.id, + })), + })) + } catch (error) { + console.error("Failed to fetch providers:", error) + return [] + } +} +``` + +### 8. Add Error Handling + +**Network error handling:** + +```typescript +function handleSDKError(error: any): string { + if (error.code === "ECONNREFUSED") { + return "Cannot connect to server. Is it running?" + } + if (error.code === "ETIMEDOUT") { + return "Request timed out. Please try again." + } + if (error.response?.status === 404) { + return "Resource not found" + } + if (error.response?.status === 500) { + return "Server error. Check logs." + } + return error.message || "Unknown error occurred" +} +``` + +**Retry logic (for transient failures):** + +```typescript +async function withRetry(fn: () => Promise, maxRetries = 3, delay = 1000): Promise { + let lastError + + for (let i = 0; i < maxRetries; i++) { + try { + return await fn() + } catch (error) { + lastError = error + if (i < maxRetries - 1) { + await new Promise((resolve) => setTimeout(resolve, delay)) + } + } + } + + throw lastError +} +``` + +### 9. Add Loading States + +**Track loading states:** + +```typescript +interface LoadingState { + fetchingSessions: Map + creatingSession: Map + deletingSession: Map> +} + +const loading: LoadingState = { + fetchingSessions: new Map(), + creatingSession: new Map(), + deletingSession: new Map(), +} +``` + +**Use in actions:** + +```typescript +async function fetchSessions(instanceId: string) { + loading.fetchingSessions.set(instanceId, true) + try { + // ... fetch logic + } finally { + loading.fetchingSessions.set(instanceId, false) + } +} +``` + +### 10. Wire Up to Instance Creation + +**src/stores/instances.ts updates:** + +**After server ready:** + +```typescript +async function createInstance(folder: string) { + // ... spawn server ... + + // Create SDK client + const client = sdkManager.createClient(port) + + // Update instance + instances.set(id, { + ...instances.get(id)!, + port, + pid, + client, + status: "ready", + }) + + // Fetch initial data + try { + await fetchSessions(id) + await fetchAgents(id) + await fetchProviders(id) + } catch (error) { + console.error("Failed to fetch initial data:", error) + // Don't fail instance creation, just log + } + + return id +} +``` + +### 11. Add Type Safety + +**src/types/session.ts:** + +```typescript +export interface Session { + id: string + instanceId: string + title: string + parentId: string | null + agent: string + model: { + providerId: string + modelId: string + } + time: { + created: number + updated: number + } +} + +export interface Agent { + name: string + description: string + mode: string +} + +export interface Provider { + id: string + name: string + models: Model[] +} + +export interface Model { + id: string + name: string + providerId: string +} +``` + +## Testing Checklist + +**Manual Tests:** + +1. Create instance → Sessions fetched automatically +2. Console shows session list +3. Create new session → Appears in list +4. Delete session → Removed from list +5. Network fails → Error message shown +6. Server not running → Graceful error + +**Error Cases:** + +- Server not responding (ECONNREFUSED) +- Request timeout +- 404 on session endpoint +- 500 server error +- Invalid session ID + +**Edge Cases:** + +- No sessions exist (empty list) +- Many sessions (100+) +- Session with very long title +- Parent-child session relationships + +## Dependencies + +- **Blocks:** Task 005 (needs session data) +- **Blocked by:** Task 003 (needs running server) + +## Estimated Time + +3-4 hours + +## Notes + +- Keep SDK calls isolated in store actions +- All SDK calls should have error handling +- Consider caching to reduce API calls +- Log all API calls for debugging +- Handle slow connections gracefully diff --git a/tasks/done/005-session-picker-modal.md b/tasks/done/005-session-picker-modal.md new file mode 100644 index 0000000..943d28c --- /dev/null +++ b/tasks/done/005-session-picker-modal.md @@ -0,0 +1,333 @@ +# Task 005: Session Picker Modal + +## Goal + +Create the session picker modal that appears when an instance starts, allowing users to resume an existing session or create a new one. + +## Prerequisites + +- Task 004 completed (SDK integration, session fetching) +- Understanding of modal/dialog patterns +- Kobalte UI primitives knowledge + +## Acceptance Criteria + +- [ ] Modal appears after instance becomes ready +- [ ] Displays list of existing sessions +- [ ] Shows session metadata (title, timestamp) +- [ ] Allows creating new session with agent selection +- [ ] Can close modal (cancels instance creation) +- [ ] Keyboard navigation works (up/down, enter) +- [ ] Properly styled and accessible +- [ ] Loading states during fetch + +## Steps + +### 1. Create Session Picker Component + +**src/components/session-picker.tsx:** + +**Props:** + +```typescript +interface SessionPickerProps { + instanceId: string + open: boolean + onClose: () => void + onSessionSelect: (sessionId: string) => void + onNewSession: (agent: string) => void +} +``` + +**Structure:** + +- Modal backdrop (semi-transparent overlay) +- Modal dialog (centered card) +- Header: "OpenCode • {folder}" +- Section 1: Resume session list +- Separator: "or" +- Section 2: Create new session +- Footer: Cancel button + +### 2. Use Kobalte Dialog + +**Implementation approach:** + +```typescript +import { Dialog } from '@kobalte/core' + + !open && props.onClose()}> + + + + {/* Modal content */} + + + +``` + +**Styling:** + +- Overlay: Dark background, 50% opacity +- Content: White card, max-width 500px, centered +- Padding: 24px +- Border radius: 8px +- Shadow: Large elevation + +### 3. Create Session List Section + +**Resume Section:** + +- Header: "Resume a session:" +- List of sessions (max 10 recent) +- Each item shows: + - Title (truncated at 50 chars) + - Relative timestamp ("2h ago") + - Hover state + - Active selection state + +**Session Item Component:** + +```typescript +interface SessionItemProps { + session: Session + selected: boolean + onClick: () => void +} +``` + +**Empty state:** + +- Show when no sessions exist +- Text: "No previous sessions" +- Muted styling + +**Scrollable:** + +- If >5 sessions, add scroll +- Max height: 300px + +### 4. Create New Session Section + +**Structure:** + +- Header: "Start new session:" +- Agent selector dropdown +- "Start" button + +**Agent Selector:** + +- Dropdown using Kobalte Select +- Shows agent name +- Grouped by category if applicable +- Default: "Build" agent + +**Start Button:** + +- Primary button style +- Click triggers onNewSession callback +- Disabled while creating + +### 5. Add Loading States + +**While fetching sessions:** + +- Show skeleton list (3-4 placeholder items) +- Shimmer animation + +**While fetching agents:** + +- Agent dropdown shows "Loading..." +- Disabled state + +**While creating session:** + +- Start button shows spinner +- Disabled state +- Text changes to "Creating..." + +### 6. Wire Up to Instance Store + +**Show modal after instance ready:** + +**src/stores/ui.ts additions:** + +```typescript +interface UIStore { + sessionPickerInstance: string | null +} + +function showSessionPicker(instanceId: string) { + sessionPickerInstance = instanceId +} + +function hideSessionPicker() { + sessionPickerInstance = null +} +``` + +**src/stores/instances.ts updates:** + +```typescript +async function createInstance(folder: string) { + // ... spawn and connect ... + + // Show session picker + showSessionPicker(id) + + return id +} +``` + +### 7. Handle Session Selection + +**Resume session:** + +```typescript +function handleSessionSelect(sessionId: string) { + setActiveSession(instanceId, sessionId) + hideSessionPicker() + + // Will trigger session display in Task 006 +} +``` + +**Create new session:** + +```typescript +async function handleNewSession(agent: string) { + try { + const session = await createSession(instanceId, agent) + setActiveSession(instanceId, session.id) + hideSessionPicker() + } catch (error) { + // Show error toast (Task 010) + console.error("Failed to create session:", error) + } +} +``` + +### 8. Handle Cancel + +**Close modal:** + +```typescript +function handleClose() { + // Remove instance since user cancelled + await removeInstance(instanceId) + hideSessionPicker() +} +``` + +**Confirmation if needed:** + +- If server already started, ask "Stop server?" +- Otherwise, just close + +### 9. Add Keyboard Navigation + +**Keyboard shortcuts:** + +- Up/Down: Navigate session list +- Enter: Select highlighted session +- Escape: Close modal (cancel) +- Tab: Cycle through sections + +**Implement focus management:** + +- Auto-focus first session on open +- Trap focus within modal +- Restore focus on close + +### 10. Add Accessibility + +**ARIA attributes:** + +- `role="dialog"` +- `aria-labelledby="dialog-title"` +- `aria-describedby="dialog-description"` +- `aria-modal="true"` + +**Screen reader support:** + +- Announce "X sessions available" +- Announce selection changes +- Clear focus indicators + +### 11. Style Refinements + +**Light/Dark mode:** + +- Test in both themes +- Ensure contrast meets WCAG AA +- Use CSS variables for colors + +**Responsive:** + +- Works at minimum window size +- Mobile-friendly (future web version) +- Scales text appropriately + +**Animations:** + +- Fade in backdrop (200ms) +- Scale in content (200ms) +- Smooth transitions on hover + +### 12. Update App Component + +**src/App.tsx:** + +**Render session picker:** + +```typescript + + {(instanceId) => ( + ui.hideSessionPicker()} + onSessionSelect={(id) => handleSessionSelect(instanceId(), id)} + onNewSession={(agent) => handleNewSession(instanceId(), agent)} + /> + )} + +``` + +## Testing Checklist + +**Manual Tests:** + +1. Create instance → Modal appears +2. Shows session list if sessions exist +3. Shows empty state if no sessions +4. Click session → Modal closes, session activates +5. Select agent, click Start → New session created +6. Press Escape → Modal closes, instance removed +7. Keyboard navigation works +8. Screen reader announces content + +**Edge Cases:** + +- No sessions + no agents (error state) +- Very long session titles (truncate) +- Many sessions (scroll works) +- Create session fails (error shown) +- Slow network (loading states) + +## Dependencies + +- **Blocks:** Task 006 (needs active session) +- **Blocked by:** Task 004 (needs session data) + +## Estimated Time + +3-4 hours + +## Notes + +- Keep modal simple and focused +- Clear call-to-action +- Don't overwhelm with options +- Loading states crucial for UX +- Consider adding search if >20 sessions (future) diff --git a/tasks/done/006-instance-session-tabs.md b/tasks/done/006-instance-session-tabs.md new file mode 100644 index 0000000..1188a75 --- /dev/null +++ b/tasks/done/006-instance-session-tabs.md @@ -0,0 +1,591 @@ +# Task 006: Instance & Session Tabs + +## Goal + +Create the two-level tab navigation system: instance tabs (Level 1) and session tabs (Level 2) that allow users to switch between projects and conversations. + +## Prerequisites + +- Task 005 completed (Session picker modal, active session selection) +- Understanding of tab navigation patterns +- Familiarity with SolidJS For/Show components +- Knowledge of keyboard accessibility + +## Acceptance Criteria + +- [ ] Instance tabs render at top level +- [ ] Session tabs render below instance tabs for active instance +- [ ] Can switch between instance tabs +- [ ] Can switch between session tabs within an instance +- [ ] Active tab is visually highlighted +- [ ] Tab labels show appropriate text (folder name, session title) +- [ ] Close buttons work on tabs (with confirmation) +- [ ] "+" button creates new instance/session +- [ ] Keyboard navigation works (Cmd/Ctrl+1-9 for tabs) +- [ ] Tabs scroll horizontally when many exist +- [ ] Properly styled and accessible + +## Steps + +### 1. Create Instance Tabs Component + +**src/components/instance-tabs.tsx:** + +**Props:** + +```typescript +interface InstanceTabsProps { + instances: Map + activeInstanceId: string | null + onSelect: (instanceId: string) => void + onClose: (instanceId: string) => void + onNew: () => void +} +``` + +**Structure:** + +```tsx +
+
+ + {([id, instance]) => ( + onSelect(id)} + onClose={() => onClose(id)} + /> + )} + + +
+
+``` + +**Styling:** + +- Horizontal layout +- Background: Secondary background color +- Border bottom: 1px solid border color +- Height: 40px +- Padding: 0 8px +- Overflow-x: auto (for many tabs) + +### 2. Create Instance Tab Item Component + +**src/components/instance-tab.tsx:** + +**Props:** + +```typescript +interface InstanceTabProps { + instance: Instance + active: boolean + onSelect: () => void + onClose: () => void +} +``` + +**Structure:** + +```tsx + + +``` + +**Styling:** + +- Display: inline-flex +- Align items center +- Gap: 8px +- Padding: 8px 12px +- Border radius: 6px 6px 0 0 +- Max width: 200px +- Truncate text with ellipsis +- Active: Background accent color +- Inactive: Transparent background +- Hover: Light background + +**Folder Name Formatting:** + +```typescript +function formatFolderName(path: string): string { + const name = path.split("/").pop() || path + return `~/${name}` +} +``` + +**Handle Duplicates:** + +- If multiple instances have same folder name, add counter +- Example: `~/project`, `~/project (2)`, `~/project (3)` + +### 3. Create Session Tabs Component + +**src/components/session-tabs.tsx:** + +**Props:** + +```typescript +interface SessionTabsProps { + instanceId: string + sessions: Map + activeSessionId: string | null + onSelect: (sessionId: string) => void + onClose: (sessionId: string) => void + onNew: () => void +} +``` + +**Structure:** + +```tsx +
+
+ + {([id, session]) => ( + onSelect(id)} + onClose={() => onClose(id)} + /> + )} + + onSelect("logs")} /> + +
+
+``` + +**Styling:** + +- Similar to instance tabs but smaller +- Height: 36px +- Font size: 13px +- Less prominent than instance tabs + +### 4. Create Session Tab Item Component + +**src/components/session-tab.tsx:** + +**Props:** + +```typescript +interface SessionTabProps { + session?: Session + special?: "logs" + active: boolean + onSelect: () => void + onClose?: () => void +} +``` + +**Structure:** + +```tsx + + + +``` + +**Styling:** + +- Max width: 150px +- Truncate with ellipsis +- Active: Underline or bold text +- Logs tab: Slightly different color/icon + +### 5. Add Tab State Management + +**src/stores/ui.ts updates:** + +```typescript +interface UIState { + instanceTabOrder: string[] + sessionTabOrder: Map + + reorderInstanceTabs: (newOrder: string[]) => void + reorderSessionTabs: (instanceId: string, newOrder: string[]) => void +} + +const [instanceTabOrder, setInstanceTabOrder] = createSignal([]) +const [sessionTabOrder, setSessionTabOrder] = createSignal>(new Map()) + +function reorderInstanceTabs(newOrder: string[]) { + setInstanceTabOrder(newOrder) +} + +function reorderSessionTabs(instanceId: string, newOrder: string[]) { + setSessionTabOrder((prev) => { + const next = new Map(prev) + next.set(instanceId, newOrder) + return next + }) +} +``` + +### 6. Wire Up Tab Selection + +**src/stores/instances.ts updates:** + +```typescript +function setActiveInstance(id: string) { + activeInstanceId = id + + // Auto-select first session or show session picker + const instance = instances.get(id) + if (instance) { + const sessions = Array.from(instance.sessions.values()) + if (sessions.length > 0 && !instance.activeSessionId) { + instance.activeSessionId = sessions[0].id + } + } +} + +function setActiveSession(instanceId: string, sessionId: string) { + const instance = instances.get(instanceId) + if (instance) { + instance.activeSessionId = sessionId + } +} +``` + +### 7. Handle Tab Close Actions + +**Close Instance Tab:** + +```typescript +async function handleCloseInstance(instanceId: string) { + const confirmed = await showConfirmDialog({ + title: "Stop OpenCode instance?", + message: `This will stop the server for ${instance.folder}`, + confirmText: "Stop Instance", + destructive: true, + }) + + if (confirmed) { + await removeInstance(instanceId) + } +} +``` + +**Close Session Tab:** + +```typescript +async function handleCloseSession(instanceId: string, sessionId: string) { + const session = getInstance(instanceId)?.sessions.get(sessionId) + + if (session && session.messages.length > 0) { + const confirmed = await showConfirmDialog({ + title: "Delete session?", + message: `This will permanently delete "${session.title}"`, + confirmText: "Delete", + destructive: true, + }) + + if (!confirmed) return + } + + await deleteSession(instanceId, sessionId) + + // Switch to another session + const instance = getInstance(instanceId) + const remainingSessions = Array.from(instance.sessions.values()) + if (remainingSessions.length > 0) { + setActiveSession(instanceId, remainingSessions[0].id) + } else { + // Show session picker + showSessionPicker(instanceId) + } +} +``` + +### 8. Handle New Tab Buttons + +**New Instance:** + +```typescript +async function handleNewInstance() { + const folder = await window.electronAPI.selectFolder() + if (folder) { + await createInstance(folder) + } +} +``` + +**New Session:** + +```typescript +async function handleNewSession(instanceId: string) { + // For now, use default agent + // Later (Task 011) will show agent selector + const session = await createSession(instanceId, "build") + setActiveSession(instanceId, session.id) +} +``` + +### 9. Update App Layout + +**src/App.tsx:** + +```tsx +
+ 0} fallback={}> + + + + {(instance) => ( + <> + setActiveSession(instance().id, id)} + onClose={(id) => handleCloseSession(instance().id, id)} + onNew={() => handleNewSession(instance().id)} + /> + +
+ {/* Message stream and input will go here in Task 007 */} + + + + +
Session content will appear here (Task 007)
+
+
+ + )} +
+
+
+``` + +### 10. Add Keyboard Shortcuts + +**Keyboard navigation:** + +```typescript +// src/lib/keyboard.ts + +export function setupTabKeyboardShortcuts() { + window.addEventListener("keydown", (e) => { + // Cmd/Ctrl + 1-9: Switch instance tabs + if ((e.metaKey || e.ctrlKey) && e.key >= "1" && e.key <= "9") { + e.preventDefault() + const index = parseInt(e.key) - 1 + const instances = Array.from(instanceStore.instances.keys()) + if (instances[index]) { + setActiveInstance(instances[index]) + } + } + + // Cmd/Ctrl + N: New instance + if ((e.metaKey || e.ctrlKey) && e.key === "n") { + e.preventDefault() + handleNewInstance() + } + + // Cmd/Ctrl + T: New session + if ((e.metaKey || e.ctrlKey) && e.key === "t") { + e.preventDefault() + if (activeInstanceId()) { + handleNewSession(activeInstanceId()!) + } + } + + // Cmd/Ctrl + W: Close current tab + if ((e.metaKey || e.ctrlKey) && e.key === "w") { + e.preventDefault() + const instanceId = activeInstanceId() + const instance = getInstance(instanceId) + if (instance?.activeSessionId && instance.activeSessionId !== "logs") { + handleCloseSession(instanceId!, instance.activeSessionId) + } + } + }) +} +``` + +**Call in main.tsx:** + +```typescript +import { setupTabKeyboardShortcuts } from "./lib/keyboard" + +onMount(() => { + setupTabKeyboardShortcuts() +}) +``` + +### 11. Add Accessibility + +**ARIA attributes:** + +```tsx +
+ +
+ +
+ {/* Session tabs */} +
+``` + +**Focus management:** + +- Tab key cycles through tabs +- Arrow keys navigate within tab list +- Focus indicators visible +- Skip links for screen readers + +### 12. Style Refinements + +**Horizontal scroll:** + +```css +.tabs-container { + display: flex; + overflow-x: auto; + overflow-y: hidden; + scrollbar-width: thin; +} + +.tabs-container::-webkit-scrollbar { + height: 4px; +} + +.tabs-container::-webkit-scrollbar-thumb { + background: var(--border-color); + border-radius: 2px; +} +``` + +**Tab animations:** + +```css +.instance-tab, +.session-tab { + transition: background-color 150ms ease; +} + +.instance-tab:hover, +.session-tab:hover { + background-color: var(--hover-background); +} + +.instance-tab.active, +.session-tab.active { + background-color: var(--active-background); +} +``` + +**Close button styling:** + +```css +.tab-close { + opacity: 0; + transition: opacity 150ms ease; +} + +.instance-tab:hover .tab-close, +.session-tab:hover .tab-close { + opacity: 1; +} + +.tab-close:hover { + background-color: var(--danger-background); + color: var(--danger-color); +} +``` + +## Testing Checklist + +**Manual Tests:** + +1. Create instance → Instance tab appears +2. Click instance tab → Switches active instance +3. Session tabs appear below active instance +4. Click session tab → Switches active session +5. Click "+" on instance tabs → Opens folder picker +6. Click "+" on session tabs → Creates new session +7. Click close on instance tab → Shows confirmation, closes +8. Click close on session tab → Closes session +9. Cmd/Ctrl+1 switches to first instance +10. Cmd/Ctrl+N opens new instance +11. Cmd/Ctrl+T creates new session +12. Cmd/Ctrl+W closes active session +13. Tabs scroll when many exist +14. Logs tab always visible and non-closable +15. Tab labels truncate long names + +**Edge Cases:** + +- Only one instance (no scrolling needed) +- Many instances (>10, horizontal scroll) +- No sessions in instance (only Logs tab visible) +- Duplicate folder names (counter added) +- Very long folder/session names (ellipsis) +- Close last session (session picker appears) +- Switch instance while session is streaming + +## Dependencies + +- **Blocks:** Task 007 (needs tab structure to display messages) +- **Blocked by:** Task 005 (needs session selection to work) + +## Estimated Time + +4-5 hours + +## Notes + +- Keep tab design clean and minimal +- Don't over-engineer tab reordering (can add later) +- Focus on functionality over fancy animations +- Ensure keyboard accessibility from the start +- Tab state will persist in Task 017 +- Context menus for tabs can be added in Task 026 diff --git a/tasks/done/007-message-display.md b/tasks/done/007-message-display.md new file mode 100644 index 0000000..6c01510 --- /dev/null +++ b/tasks/done/007-message-display.md @@ -0,0 +1,812 @@ +# Task 007: Message Display + +## Goal + +Create the message display component that renders user and assistant messages in a scrollable stream, showing message content, tool calls, and streaming states. + +> Note: This legacy task predates `message-stream-v2` and the normalized message store; the new implementation lives under `packages/ui/src/components/message-stream-v2.tsx`. + +## Prerequisites + +- Task 006 completed (Tab navigation in place) +- Understanding of message part structure from OpenCode SDK +- Familiarity with markdown rendering +- Knowledge of SolidJS For/Show components + +## Acceptance Criteria + +- [ ] Messages render in chronological order +- [ ] User messages display with correct styling +- [ ] Assistant messages display with agent label +- [ ] Text content renders properly +- [ ] Tool calls display inline with collapse/expand +- [ ] Auto-scroll to bottom on new messages +- [ ] Manual scroll up disables auto-scroll +- [ ] "Scroll to bottom" button appears when scrolled up +- [ ] Empty state shows when no messages +- [ ] Loading state shows when fetching messages +- [ ] Timestamps display for each message +- [ ] Messages are accessible and keyboard-navigable + +## Steps + +### 1. Define Message Types + +**src/types/message.ts:** + +```typescript +export interface Message { + id: string + sessionId: string + type: "user" | "assistant" + parts: MessagePart[] + timestamp: number + status: "sending" | "sent" | "streaming" | "complete" | "error" +} + +export type MessagePart = TextPart | ToolCallPart | ToolResultPart | ErrorPart + +export interface TextPart { + type: "text" + text: string +} + +export interface ToolCallPart { + type: "tool_call" + id: string + tool: string + input: any + status: "pending" | "running" | "success" | "error" +} + +export interface ToolResultPart { + type: "tool_result" + toolCallId: string + output: any + error?: string +} + +export interface ErrorPart { + type: "error" + message: string +} +``` + +### 2. Create Message Stream Component + +**src/components/message-stream.tsx:** + +```typescript +import { For, Show, createSignal, onMount, onCleanup } from "solid-js" +import { Message } from "../types/message" +import MessageItem from "./message-item" + +interface MessageStreamProps { + sessionId: string + messages: Message[] + loading?: boolean +} + +export default function MessageStream(props: MessageStreamProps) { + let containerRef: HTMLDivElement | undefined + const [autoScroll, setAutoScroll] = createSignal(true) + const [showScrollButton, setShowScrollButton] = createSignal(false) + + function scrollToBottom() { + if (containerRef) { + containerRef.scrollTop = containerRef.scrollHeight + setAutoScroll(true) + setShowScrollButton(false) + } + } + + function handleScroll() { + if (!containerRef) return + + const { scrollTop, scrollHeight, clientHeight } = containerRef + const isAtBottom = scrollHeight - scrollTop - clientHeight < 50 + + setAutoScroll(isAtBottom) + setShowScrollButton(!isAtBottom) + } + + onMount(() => { + if (autoScroll()) { + scrollToBottom() + } + }) + + // Auto-scroll when new messages arrive + const messagesLength = () => props.messages.length + createEffect(() => { + messagesLength() // Track changes + if (autoScroll()) { + setTimeout(scrollToBottom, 0) + } + }) + + return ( +
+
+ +
+
+

Start a conversation

+

Type a message below or try:

+
    +
  • /init-project
  • +
  • Ask about your codebase
  • +
  • Attach files with @
  • +
+
+
+
+ + +
+
+

Loading messages...

+
+ + + + {(message) => ( + + )} + +
+ + + + +
+ ) +} +``` + +### 3. Create Message Item Component + +**src/components/message-item.tsx:** + +```typescript +import { For, Show } from "solid-js" +import { Message } from "../types/message" +import MessagePart from "./message-part" + +interface MessageItemProps { + message: Message +} + +export default function MessageItem(props: MessageItemProps) { + const isUser = () => props.message.type === "user" + const timestamp = () => { + const date = new Date(props.message.timestamp) + return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) + } + + return ( +
+
+ + {isUser() ? "You" : "Assistant"} + + {timestamp()} +
+ +
+ + {(part) => } + +
+ + +
+ ⚠ Message failed to send +
+
+
+ ) +} +``` + +### 4. Create Message Part Component + +**src/components/message-part.tsx:** + +```typescript +import { Show, Match, Switch } from "solid-js" +import { MessagePart as MessagePartType } from "../types/message" +import ToolCall from "./tool-call" + +interface MessagePartProps { + part: MessagePartType +} + +export default function MessagePart(props: MessagePartProps) { + return ( + + +
+ {(props.part as any).text} +
+
+ + + + + + +
+ ⚠ {(props.part as any).message} +
+
+
+ ) +} +``` + +### 5. Create Tool Call Component + +**src/components/tool-call.tsx:** + +```typescript +import { createSignal, Show } from "solid-js" +import { ToolCallPart } from "../types/message" + +interface ToolCallProps { + toolCall: ToolCallPart +} + +export default function ToolCall(props: ToolCallProps) { + const [expanded, setExpanded] = createSignal(false) + + const statusIcon = () => { + switch (props.toolCall.status) { + case "pending": + return "⏳" + case "running": + return "⏳" + case "success": + return "✓" + case "error": + return "✗" + default: + return "" + } + } + + const statusClass = () => { + return `tool-call-status-${props.toolCall.status}` + } + + function toggleExpanded() { + setExpanded(!expanded()) + } + + function formatToolSummary() { + // Create a brief summary of the tool call + const { tool, input } = props.toolCall + + switch (tool) { + case "bash": + return `bash: ${input.command}` + case "edit": + return `edit ${input.filePath}` + case "read": + return `read ${input.filePath}` + case "write": + return `write ${input.filePath}` + default: + return `${tool}` + } + } + + return ( +
+ + + +
+
+

Input:

+
{JSON.stringify(props.toolCall.input, null, 2)}
+
+ + +
+

Output:

+
{formatToolOutput()}
+
+
+
+
+
+ ) + + function formatToolOutput() { + // This will be enhanced in later tasks + // For now, just stringify + return "Output will be displayed here" + } +} +``` + +### 6. Add Message Store Integration + +**src/stores/sessions.ts updates:** + +```typescript +interface Session { + // ... existing fields + messages: Message[] +} + +async function loadMessages(instanceId: string, sessionId: string) { + const instance = getInstance(instanceId) + if (!instance) return + + try { + // Fetch messages from SDK + const response = await instance.client.session.getMessages(sessionId) + + // Update session with messages + const session = instance.sessions.get(sessionId) + if (session) { + session.messages = response.messages.map(transformMessage) + } + } catch (error) { + console.error("Failed to load messages:", error) + throw error + } +} + +function transformMessage(apiMessage: any): Message { + return { + id: apiMessage.id, + sessionId: apiMessage.sessionId, + type: apiMessage.type, + parts: apiMessage.parts || [], + timestamp: apiMessage.timestamp || Date.now(), + status: "complete", + } +} +``` + +### 7. Update App to Show Messages + +**src/App.tsx updates:** + +```tsx + + {() => { + const session = instance().sessions.get(instance().activeSessionId!) + + return ( + Session not found
}> + {(s) => } + + ) + }} + +``` + +### 8. Add Styling + +**src/components/message-stream.css:** + +```css +.message-stream-container { + position: relative; + flex: 1; + display: flex; + flex-direction: column; + overflow: hidden; +} + +.message-stream { + flex: 1; + overflow-y: auto; + padding: 16px; + display: flex; + flex-direction: column; + gap: 16px; +} + +.message-item { + display: flex; + flex-direction: column; + gap: 8px; + padding: 12px 16px; + border-radius: 8px; + max-width: 85%; +} + +.message-item.user { + align-self: flex-end; + background-color: var(--user-message-bg); +} + +.message-item.assistant { + align-self: flex-start; + background-color: var(--assistant-message-bg); +} + +.message-header { + display: flex; + justify-content: space-between; + align-items: center; + gap: 12px; +} + +.message-sender { + font-weight: 600; + font-size: 14px; +} + +.message-timestamp { + font-size: 12px; + color: var(--text-muted); +} + +.message-content { + display: flex; + flex-direction: column; + gap: 8px; +} + +.message-text { + font-size: 14px; + line-height: 1.5; + white-space: pre-wrap; + word-wrap: break-word; +} + +.tool-call { + margin: 8px 0; + border: 1px solid var(--border-color); + border-radius: 6px; + overflow: hidden; +} + +.tool-call-header { + display: flex; + align-items: center; + gap: 8px; + padding: 8px 12px; + width: 100%; + background-color: var(--secondary-bg); + border: none; + cursor: pointer; + font-family: monospace; + font-size: 13px; +} + +.tool-call-header:hover { + background-color: var(--hover-bg); +} + +.tool-call-icon { + font-size: 10px; +} + +.tool-call-summary { + flex: 1; + text-align: left; +} + +.tool-call-status { + font-size: 14px; +} + +.tool-call-status-success { + border-left: 3px solid var(--success-color); +} + +.tool-call-status-error { + border-left: 3px solid var(--error-color); +} + +.tool-call-status-running { + border-left: 3px solid var(--warning-color); +} + +.tool-call-details { + padding: 12px; + background-color: var(--code-bg); + display: flex; + flex-direction: column; + gap: 12px; +} + +.tool-call-section h4 { + font-size: 12px; + font-weight: 600; + margin-bottom: 4px; + color: var(--text-muted); +} + +.tool-call-section pre { + margin: 0; + padding: 8px; + background-color: var(--background); + border-radius: 4px; + overflow-x: auto; +} + +.tool-call-section code { + font-family: monospace; + font-size: 12px; + line-height: 1.4; +} + +.scroll-to-bottom { + position: absolute; + bottom: 16px; + right: 16px; + width: 40px; + height: 40px; + border-radius: 50%; + background-color: var(--accent-color); + color: white; + border: none; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); + cursor: pointer; + font-size: 20px; + display: flex; + align-items: center; + justify-content: center; + transition: transform 150ms ease; +} + +.scroll-to-bottom:hover { + transform: scale(1.1); +} + +.empty-state { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + padding: 48px; +} + +.empty-state-content { + text-align: center; + max-width: 400px; +} + +.empty-state-content h3 { + font-size: 18px; + margin-bottom: 12px; +} + +.empty-state-content p { + font-size: 14px; + color: var(--text-muted); + margin-bottom: 16px; +} + +.empty-state-content ul { + list-style: none; + padding: 0; + display: flex; + flex-direction: column; + gap: 8px; +} + +.empty-state-content li { + font-size: 14px; + color: var(--text-muted); +} + +.empty-state-content code { + background-color: var(--code-bg); + padding: 2px 6px; + border-radius: 3px; + font-family: monospace; + font-size: 13px; +} + +.loading-state { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 16px; + padding: 48px; +} + +.spinner { + width: 32px; + height: 32px; + border: 3px solid var(--border-color); + border-top-color: var(--accent-color); + border-radius: 50%; + animation: spin 1s linear infinite; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} +``` + +### 9. Add CSS Variables + +**src/index.css updates:** + +```css +:root { + /* Message colors */ + --user-message-bg: #e3f2fd; + --assistant-message-bg: #f5f5f5; + + /* Status colors */ + --success-color: #4caf50; + --error-color: #f44336; + --warning-color: #ff9800; + + /* Code colors */ + --code-bg: #f8f8f8; +} + +[data-theme="dark"] { + --user-message-bg: #1e3a5f; + --assistant-message-bg: #2a2a2a; + --code-bg: #1a1a1a; +} +``` + +### 10. Load Messages on Session Switch + +**src/hooks/use-session.ts:** + +```typescript +import { createEffect } from "solid-js" + +export function useSession(instanceId: string, sessionId: string) { + createEffect(() => { + // Load messages when session becomes active + if (sessionId && sessionId !== "logs") { + loadMessages(instanceId, sessionId).catch(console.error) + } + }) +} +``` + +**Use in App.tsx:** + +```tsx + + {(s) => { + useSession(instance().id, s().id) + + return + }} + +``` + +### 11. Add Accessibility + +**ARIA attributes:** + +```tsx +
+ {/* Messages */} +
+ +
+ {/* Message content */} +
+``` + +**Keyboard navigation:** + +- Messages should be accessible via Tab key +- Tool calls can be expanded with Enter/Space +- Screen readers announce new messages + +### 12. Handle Long Messages + +**Text wrapping:** + +```css +.message-text { + overflow-wrap: break-word; + word-wrap: break-word; + hyphens: auto; +} +``` + +**Code blocks (for now, just basic):** + +```css +.message-text pre { + overflow-x: auto; + padding: 8px; + background-color: var(--code-bg); + border-radius: 4px; +} +``` + +## Testing Checklist + +**Manual Tests:** + +1. Empty session shows empty state +2. Messages load when switching sessions +3. User messages appear on right +4. Assistant messages appear on left +5. Timestamps display correctly +6. Tool calls appear inline +7. Tool calls expand/collapse on click +8. Auto-scroll works for new messages +9. Manual scroll up disables auto-scroll +10. Scroll to bottom button appears/works +11. Long messages wrap correctly +12. Multiple messages display properly +13. Messages are keyboard accessible + +**Edge Cases:** + +- Session with 1 message +- Session with 100+ messages +- Messages with very long text +- Messages with no parts +- Tool calls with large output +- Rapid message updates +- Switching sessions while loading + +## Dependencies + +- **Blocks:** Task 008 (SSE will update these messages in real-time) +- **Blocked by:** Task 006 (needs tab structure) + +## Estimated Time + +4-5 hours + +## Notes + +- Keep styling simple for now - markdown rendering comes in Task 012 +- Tool output formatting will be enhanced in Task 010 +- Focus on basic text display and structure +- Don't optimize for virtual scrolling yet (MVP principle) +- Message actions (copy, edit, etc.) come in Task 026 +- This is the foundation for real-time updates in Task 008 diff --git a/tasks/done/008-sse-integration.md b/tasks/done/008-sse-integration.md new file mode 100644 index 0000000..ec49de6 --- /dev/null +++ b/tasks/done/008-sse-integration.md @@ -0,0 +1,445 @@ +# Task 008: SSE Integration - Real-time Message Streaming + +> Note: References to `message-stream.tsx` here are legacy; the current UI uses `message-stream-v2.tsx` with the normalized message store. + +## Status: TODO + +## Objective + +Implement Server-Sent Events (SSE) integration to enable real-time message streaming from OpenCode servers. Each instance will maintain its own EventSource connection to receive live updates for sessions and messages. + +## Prerequisites + +- Task 006 (Instance/Session tabs) complete +- Task 007 (Message display) complete +- SDK client configured per instance +- Understanding of EventSource API + +## Context + +The OpenCode server emits events via SSE at the `/events` endpoint. These events include: + +- Message updates (streaming content) +- Session updates (new sessions, title changes) +- Tool execution status updates +- Server status changes + +We need to: + +1. Create an SSE manager to handle connections +2. Connect one EventSource per instance +3. Route events to the correct instance/session +4. Update reactive state to trigger UI updates +5. Implement reconnection logic for dropped connections + +## Implementation Steps + +### Step 1: Create SSE Manager Module + +Create `src/lib/sse-manager.ts`: + +```typescript +import { createSignal } from "solid-js" + +interface SSEConnection { + instanceId: string + eventSource: EventSource + reconnectAttempts: number + status: "connecting" | "connected" | "disconnected" | "error" +} + +interface MessageUpdateEvent { + type: "message_updated" + sessionId: string + messageId: string + parts: any[] + status: string +} + +interface SessionUpdateEvent { + type: "session_updated" + session: any +} + +class SSEManager { + private connections = new Map() + private maxReconnectAttempts = 5 + private baseReconnectDelay = 1000 + + connect(instanceId: string, port: number): void { + if (this.connections.has(instanceId)) { + this.disconnect(instanceId) + } + + const url = `http://localhost:${port}/events` + const eventSource = new EventSource(url) + + const connection: SSEConnection = { + instanceId, + eventSource, + reconnectAttempts: 0, + status: "connecting", + } + + this.connections.set(instanceId, connection) + + eventSource.onopen = () => { + connection.status = "connected" + connection.reconnectAttempts = 0 + console.log(`[SSE] Connected to instance ${instanceId}`) + } + + eventSource.onmessage = (event) => { + try { + const data = JSON.parse(event.data) + this.handleEvent(instanceId, data) + } catch (error) { + console.error("[SSE] Failed to parse event:", error) + } + } + + eventSource.onerror = () => { + connection.status = "error" + console.error(`[SSE] Connection error for instance ${instanceId}`) + this.handleReconnect(instanceId, port) + } + } + + disconnect(instanceId: string): void { + const connection = this.connections.get(instanceId) + if (connection) { + connection.eventSource.close() + this.connections.delete(instanceId) + console.log(`[SSE] Disconnected from instance ${instanceId}`) + } + } + + private handleEvent(instanceId: string, event: any): void { + switch (event.type) { + case "message_updated": + this.onMessageUpdate?.(instanceId, event as MessageUpdateEvent) + break + case "session_updated": + this.onSessionUpdate?.(instanceId, event as SessionUpdateEvent) + break + default: + console.warn("[SSE] Unknown event type:", event.type) + } + } + + private handleReconnect(instanceId: string, port: number): void { + const connection = this.connections.get(instanceId) + if (!connection) return + + if (connection.reconnectAttempts >= this.maxReconnectAttempts) { + console.error(`[SSE] Max reconnection attempts reached for ${instanceId}`) + connection.status = "disconnected" + return + } + + const delay = this.baseReconnectDelay * Math.pow(2, connection.reconnectAttempts) + connection.reconnectAttempts++ + + console.log(`[SSE] Reconnecting to ${instanceId} in ${delay}ms (attempt ${connection.reconnectAttempts})`) + + setTimeout(() => { + this.connect(instanceId, port) + }, delay) + } + + onMessageUpdate?: (instanceId: string, event: MessageUpdateEvent) => void + onSessionUpdate?: (instanceId: string, event: SessionUpdateEvent) => void + + getStatus(instanceId: string): SSEConnection["status"] | null { + return this.connections.get(instanceId)?.status ?? null + } +} + +export const sseManager = new SSEManager() +``` + +### Step 2: Integrate SSE Manager with Instance Store + +Update `src/stores/instances.ts` to use SSE manager: + +```typescript +import { sseManager } from "../lib/sse-manager" + +// In createInstance function, after SDK client is created: +async function createInstance(folder: string) { + // ... existing code to spawn server and create SDK client ... + + // Connect SSE + sseManager.connect(instance.id, port) + + // Set up event handlers + sseManager.onMessageUpdate = (instanceId, event) => { + handleMessageUpdate(instanceId, event) + } + + sseManager.onSessionUpdate = (instanceId, event) => { + handleSessionUpdate(instanceId, event) + } +} + +// In removeInstance function: +async function removeInstance(id: string) { + // Disconnect SSE before removing + sseManager.disconnect(id) + + // ... existing cleanup code ... +} +``` + +### Step 3: Handle Message Update Events + +Create message update handler in instance store: + +```typescript +function handleMessageUpdate(instanceId: string, event: MessageUpdateEvent) { + const instance = instances.get(instanceId) + if (!instance) return + + const session = instance.sessions.get(event.sessionId) + if (!session) return + + // Find or create message + let message = session.messages.find((m) => m.id === event.messageId) + + if (!message) { + // New message - add it + message = { + id: event.messageId, + sessionId: event.sessionId, + type: "assistant", // Determine from event + parts: event.parts, + timestamp: Date.now(), + status: event.status, + } + session.messages.push(message) + } else { + // Update existing message + message.parts = event.parts + message.status = event.status + } + + // Trigger reactivity - update the map reference + instances.set(instanceId, { ...instance }) +} +``` + +### Step 4: Handle Session Update Events + +Create session update handler: + +```typescript +function handleSessionUpdate(instanceId: string, event: SessionUpdateEvent) { + const instance = instances.get(instanceId) + if (!instance) return + + const existingSession = instance.sessions.get(event.session.id) + + if (!existingSession) { + // New session - add it + const newSession = { + id: event.session.id, + instanceId, + title: event.session.title || "Untitled", + parentId: event.session.parentId, + agent: event.session.agent, + model: event.session.model, + messages: [], + status: "idle", + createdAt: Date.now(), + updatedAt: Date.now(), + } + + instance.sessions.set(event.session.id, newSession) + + // Auto-create tab for child sessions + if (event.session.parentId) { + console.log(`[SSE] New child session created: ${event.session.id}`) + // Optionally auto-switch to new session + // instance.activeSessionId = event.session.id + } + } else { + // Update existing session + existingSession.title = event.session.title || existingSession.title + existingSession.agent = event.session.agent || existingSession.agent + existingSession.model = event.session.model || existingSession.model + existingSession.updatedAt = Date.now() + } + + // Trigger reactivity + instances.set(instanceId, { ...instance }) +} +``` + +### Step 5: Add Connection Status Indicator + +Update `src/components/message-stream.tsx` to show connection status: + +```typescript +import { sseManager } from "../lib/sse-manager" + +function MessageStream(props) { + const connectionStatus = () => sseManager.getStatus(props.instanceId) + + return ( +
+ {/* Connection status indicator */} +
+ {connectionStatus() === "connected" && ( + +
+ Connected + + )} + {connectionStatus() === "connecting" && ( + +
+ Connecting... + + )} + {connectionStatus() === "error" && ( + +
+ Disconnected + + )} +
+ + {/* Existing message list */} + {/* ... */} +
+ ) +} +``` + +### Step 6: Test SSE Connection + +Create a test utility to verify SSE is working: + +```typescript +// In browser console or test file: +async function testSSE() { + // Manually trigger a message + const response = await fetch("http://localhost:4096/session/SESSION_ID/message", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + prompt: "Hello, world!", + attachments: [], + }), + }) + + // Check console for SSE events + // Should see message_updated events arriving +} +``` + +### Step 7: Handle Edge Cases + +Add error handling for: + +```typescript +// Connection drops during message streaming +// - Reconnect logic should handle this automatically +// - Messages should resume from last known state + +// Multiple instances with different ports +// - Each instance has its own EventSource +// - Events routed correctly via instanceId + +// Instance removed while connected +// - EventSource closed before instance cleanup +// - No memory leaks + +// Page visibility changes (browser tab inactive) +// - EventSource may pause, reconnect on focus +// - Consider using Page Visibility API to manage connections +``` + +## Testing Checklist + +### Manual Testing + +- [ ] Open instance, verify SSE connection established +- [ ] Send message, verify streaming events arrive +- [ ] Check browser DevTools Network tab for SSE connection +- [ ] Verify connection status indicator shows "Connected" +- [ ] Kill server process, verify reconnection attempts +- [ ] Restart server, verify successful reconnection +- [ ] Open multiple instances, verify independent connections +- [ ] Switch between instances, verify events route correctly +- [ ] Close instance tab, verify EventSource closed cleanly + +### Testing Message Streaming + +- [ ] Send message, watch events in console +- [ ] Verify message parts update in real-time +- [ ] Check assistant response streams character by character +- [ ] Verify tool calls appear as they execute +- [ ] Confirm message status updates (streaming → complete) + +### Testing Child Sessions + +- [ ] Trigger action that creates child session +- [ ] Verify session_updated event received +- [ ] Confirm new session tab appears +- [ ] Check parentId correctly set + +### Testing Reconnection + +- [ ] Disconnect network, verify reconnection attempts +- [ ] Reconnect network, verify successful reconnection +- [ ] Verify exponential backoff delays +- [ ] Confirm max attempts limit works + +## Acceptance Criteria + +- [ ] SSE connection established when instance created +- [ ] Message updates arrive in real-time +- [ ] Session updates handled correctly +- [ ] Child sessions auto-create tabs +- [ ] Connection status visible in UI +- [ ] Reconnection logic works with exponential backoff +- [ ] Multiple instances have independent connections +- [ ] EventSource closed when instance removed +- [ ] No console errors during normal operation +- [ ] Events route to correct instance/session + +## Performance Considerations + +**Note: Per MVP principles, don't over-optimize** + +- Simple event handling - no batching needed +- Direct state updates trigger reactivity +- Reconnection uses exponential backoff +- Only optimize if lag occurs in testing + +## Future Enhancements (Post-MVP) + +- Event batching for high-frequency updates +- Delta updates instead of full message parts +- Offline queue for events missed during disconnect +- Page Visibility API integration +- Event compression for large payloads + +## References + +- [Technical Implementation - SSE Event Handling](../docs/technical-implementation.md#sse-event-handling) +- [Architecture - Communication Layer](../docs/architecture.md#communication-layer) +- [MDN - EventSource API](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) + +## Estimated Time + +3-4 hours + +## Notes + +- Keep reconnection logic simple for MVP +- Log all SSE events to console for debugging +- Test with long-running streaming responses +- Verify memory usage doesn't grow over time +- Consider adding SSE event debugging panel (optional) diff --git a/tasks/done/009-prompt-input-basic.md b/tasks/done/009-prompt-input-basic.md new file mode 100644 index 0000000..63c7618 --- /dev/null +++ b/tasks/done/009-prompt-input-basic.md @@ -0,0 +1,520 @@ +# Task 009: Prompt Input Basic - Text Input with Send Functionality + +## Status: TODO + +## Objective + +Implement a basic prompt input component that allows users to type messages and send them to the OpenCode server. This enables testing of the SSE integration and completes the core chat interface loop. + +## Prerequisites + +- Task 007 (Message display) complete +- Task 008 (SSE integration) complete +- Active session available +- SDK client configured + +## Context + +The prompt input is the primary way users interact with OpenCode. For the MVP, we need: + +- Simple text input (multi-line textarea) +- Send button +- Basic keyboard shortcuts (Enter to send, Shift+Enter for new line) +- Loading state while assistant is responding +- Basic validation (empty message prevention) + +Advanced features (slash commands, file attachments, @ mentions) will come in Task 021-024. + +## Implementation Steps + +### Step 1: Create Prompt Input Component + +Create `src/components/prompt-input.tsx`: + +```typescript +import { createSignal, Show } from "solid-js" + +interface PromptInputProps { + instanceId: string + sessionId: string + onSend: (prompt: string) => Promise + disabled?: boolean +} + +export default function PromptInput(props: PromptInputProps) { + const [prompt, setPrompt] = createSignal("") + const [sending, setSending] = createSignal(false) + let textareaRef: HTMLTextAreaElement | undefined + + function handleKeyDown(e: KeyboardEvent) { + if (e.key === "Enter" && !e.shiftKey) { + e.preventDefault() + handleSend() + } + } + + async function handleSend() { + const text = prompt().trim() + if (!text || sending() || props.disabled) return + + setSending(true) + try { + await props.onSend(text) + setPrompt("") + + // Auto-resize textarea back to initial size + if (textareaRef) { + textareaRef.style.height = "auto" + } + } catch (error) { + console.error("Failed to send message:", error) + alert("Failed to send message: " + (error instanceof Error ? error.message : String(error))) + } finally { + setSending(false) + textareaRef?.focus() + } + } + + function handleInput(e: Event) { + const target = e.target as HTMLTextAreaElement + setPrompt(target.value) + + // Auto-resize textarea + target.style.height = "auto" + target.style.height = Math.min(target.scrollHeight, 200) + "px" + } + + const canSend = () => prompt().trim().length > 0 && !sending() && !props.disabled + + return ( +
+
+